I want to query the meta data in Cognos 8 to find all report and column names. If possible, I'd like to include the column definitions.
Can I do this using a Cognos report or do I need to query some repository?
Thanks.
You can select a list of reports from the content store with the following query:
SELECT CMOBJNAMES_BASE.NAME AS ObjName, CMOBJECTS.PCMID, CMCLASSES.NAME AS ClassName, CMOBJPROPS7.spec
FROM CMOBJECTS
JOIN CMOBJNAMES_BASE ON CMOBJECTS.CMID = CMOBJNAMES_BASE.CMID
JOIN CMCLASSES ON CMOBJECTS.CLASSID = CMCLASSES.CLASSID
LEFT JOIN CMOBJPROPS7 ON CMOBJECTS.CMID = CMOBJPROPS7.CMID
WHERE CMOBJECTS.CLASSID IN (10, 37)
ORDER BY CMOBJECTS.PCMID;
I use that in Cognos 10. I believe in cognos 8 the CMOBJNAMES_BASE table is actually named 'CMOBJNAMES' without the _BASE.
UPDATE: Has been tested and works in Cognos 11r9.
The Report metadata is stored in the 'SPEC' column of CMOBJPROPS7 as XML. You can parse this XML in order to strip out the columns used in the report. It will not be a simple task.
If you have time but not money, you can write your own code to parse that XML. If you have more money than time, you can buy a 3rd party program to accomplish this, such as Motio or BSP Metamanager.
The query above is less useful for building a clean list of columns, but great for searching for specific data items. For example, you have column you are wanting to change in a data source, but you are not sure which report uses that column. Run the query above, and search for the data item. It will be embedded within the XML in the Cognos MDX format, ie. [Presentation View].[Sales Summary].[Sales]
EDIT: As requested below, here is a query that includes folder paths.
-- List of Reports, the folder they are in, and the package they are using
select distinct temp2.name as package,temp1.folder,temp1.name from
(SELECT temp.PARENTNAME AS FOLDER,CMOBJECTS.PCMID,CMOBJNAMES.CMID, CMOBJNAMES.LOCALEID, CMOBJNAMES.MAPDLOCALEID, CMOBJNAMES.ISDEFAULT, CMOBJNAMES.NAME,
CMOBJECTS.CLASSID
FROM CMOBJNAMES INNER JOIN
CMOBJECTS ON CMOBJNAMES.CMID = CMOBJECTS.CMID
INNER JOIN
(SELECT P.CMID AS PARENT,P.NAME AS PARENTNAME FROM CMOBJNAMES P where P.LOCALEID between 24 and 52) temp
ON CMOBJECTS.PCMID = TEMP.PARENT
WHERE (CMOBJECTS.CLASSID = 10)
AND SUBSTR(TEMP.PARENTNAME,1,1) NOT IN ('1','2','3','4','5','6','7','8','9') AND
TEMP.PARENTNAME NOT LIKE 'Backup%') temp1
inner join
(SELECT CMREFNOORD1.CMID AS PID, CMREFNOORD1.REFCMID, CMOBJNAMES.NAME
FROM CMREFNOORD1 INNER JOIN
CMOBJECTS ON CMREFNOORD1.REFCMID = CMOBJECTS.CMID INNER JOIN
CMOBJNAMES ON CMOBJECTS.CMID = CMOBJNAMES.CMID
WHERE (CMREFNOORD1.PROPID = 31 AND CMOBJNAMES.LOCALEID between 24 and 52)) temp2
on temp1.cmid = temp2.pid and LOCALEID between 24 and 52;
Not sure if this will help anybody, but our version doesn't have a table named CMOBJNAMES_BASE.
This is what works for me:
select ob2.cmid, c.name as classname, n.name as objectname, o.DELIVOPTIONS as deliveryoptions, z2.name as owner
from CMOBJPROPS2 p
inner join CMOBJPROPS26 o on p.cmid=o.cmid
inner join CMOBJECTS ob on ob.cmid=o.cmid
inner join CMOBJECTS ob2 on ob.pcmid=ob2.cmid
inner join CMOBJNAMES n on n.cmid=ob2.cmid
inner join CMCLASSES c on ob2.classid=c.classid
left join CMREFNOORD2 z1 on z1.cmid = p.cmid
left join CMOBJPROPS33 z2 on z2.CMID = z1.REFCMID
where ACTIVE = 1 order by z2.name, objectName
Related
I have only been using Toad/Oracle for a few weeks so am still learning coding etc I have knowledge of SQL Code in Access and trying to now learn Oracle.
I need to return the max date from UCMRBILDAT from tbl BIC/AZUCDMO0100 but only from contracts which are contained in linked tbl LH_DAT
I have also tried a having MAX UCMRBILDAT but this didnt work.
UCMRBILDAT (/BIC/AZUCDMO0100)
UC_MRESULT (/BIC/AZUCDMO0100)
UC_MRSTAT (/BIC/AZUCDMO0100
UC_MRCAT (/BIC/AZUCDMO0100)
CONTRACT_NUMBER (LH_DAT)
UC_MR_NUMB (/BIC/AZUCDMO0100) + (/BIC/AZUCDMO0200)
SELECT UCMRBILDAT,
UC_MRESULT,
UC_MRSTAT,
UC_MRCAT
FROM LH_DAT
( SELECT CONTRACT_NUMBER, MAX (UCMRBILDAT) MXBD
FROM SAPSR3."/BIC/AZUCDMO0100"
GROUP BY CONTRACT_NUMBER) GMR
LEFT OUTER JOIN SAPSR3."/BIC/AZUCDMO0200"
ON (CONTRACT_NUMBER = UCCONTRACT)
INNER JOIN SAPSR3."/BIC/AZUCDMO0100"
ON ("/BIC/AZUCDMO0200".UC_MR_NUMB = "/BIC/AZUCDMO0100".UC_MR_NUMB)
WHERE CONTRACT_NUMBER = '2000014420'
AND UCMRBILDAT = MXBD
AND MR.CONTRACT_NUMBER = GMR.CONTRACT_NUMBER
Max bill date from BIC/AZUCDMO0100 but only for contracts contained in table LH_DAT
EDIT NEED MAX DATE FOR UCMRBILDAT ON BELOW SCRIPT
SELECT CONTRACT_NUMBER,
UCMRBILDAT,
UC_MRESULT,
UC_MRCAT
FROM LH_DAT
LEFT OUTER JOIN SAPSR3."/BIC/AZUCDMO0200"
ON (CONTRACT_NUMBER = UCCONTRACT)
INNER JOIN SAPSR3."/BIC/AZUCDMO0100"
ON ("/BIC/AZUCDMO0200".UC_MR_NUMB = "/BIC/AZUCDMO0100".UC_MR_NUMB)
WHERE CONTRACT_NUMBER = '2000014420'
AND "/BIC/AZUCDMO0200".SOURSYSTEM = 'SP'
AND "/BIC/AZUCDMO0200".UCDELE_IND <> 'X'
To get the max value of "BIC/AZUCDMO0100".UCMRBILDAT where there's a linked value from LH_DAT you'd want to use:
SELECT MAX(ba.UCMRBILDAT)
FROM SAPSR3."BIC/AZUCDMO0100" ba
INNER JOIN LH_DAT ld
ON ld.some_field = ba.some_field
There must be fields which link "BIC/AZUCDMO0100" and LH_DAT together, but in your query they're not specified. Find those fields, plug them in to the query above, and you should get the result you're looking for.
How can I simplify this query?
What I am trying to do is derive the column S9_Unlock via a subquery in which I only look for user_ids which are returned from the main query but this looks very awkward to me, especially as this query here is just an excerpt. In reality I am doing multiple of these subqueries to derive different columns...
SELECT userid, CAST(to_char(S9_unlock,'YYYY/MM/DD') AS timestamp) AS "S9_Unlock"
FROM (
SELECT ca.user_id AS userid
FROM shop_db.invoices AS inv
LEFT JOIN shop_db.carts AS ca ON inv.id = ca.invoice_id
LEFT JOIN shop_db.cart_items AS ci ON ca.id = ci.cart_id
WHERE (inv.created BETWEEN '2014-11-13' AND '2014-11-14' OR inv.created BETWEEN '2013-11-14' AND '2013-11-15')
AND inv.status <> 'do_not_book'
AND inv.id IS NOT NULL
GROUP BY user_id) AS master
LEFT JOIN (
SELECT MIN(s3.unl) AS "S9_Unlock", s3.user_id
FROM (
SELECT user_id, challenge_codes.created AS unl,
MAX /* Check if license contains Suite9 */
(CASE WHEN substring(bundle_article_code,1,6) = 'BuSu90' THEN 1 ELSE 0 END) AS "S9_Unlock"
FROM licensing_db.serial_numbers
LEFT JOIN licensing_db.licenses ON licenses.id = serial_numbers.license_id
LEFT JOIN user_db.users ON users.id = licenses.user_id
LEFT JOIN licensing_db.challenge_codes ON challenge_codes.serial_number_id = serial_numbers.id
WHERE user_id IN (
SELECT ca.user_id AS userid
FROM shop_db.invoices AS inv
LEFT JOIN shop_db.carts AS ca ON inv.id = ca.invoice_id
LEFT JOIN shop_db.cart_items AS ci ON ca.id = ci.cart_id
WHERE (inv.created BETWEEN '2014-11-13' AND '2014-11-14' OR inv.created BETWEEN '2013-11-14' AND '2013-11-15')
AND inv.status <> 'do_not_book'
AND inv.id IS NOT NULL
GROUP BY user_id
)
GROUP BY user_id, challenge_codes.created) AS s3
)
WHERE "S9_Unlock" = 1
AND s3.unl IS NOT NULL
GROUP BY s3.user_id) AS "S9_Unlock" ON "S9_Unlock".user_id = master.userid
In your query you have two sub-queries that are identical; this screams for a CTE.
In the sub-query on licensing issues you can filter out the valid licenses after the GROUP BY clause using a HAVING clause. Make that a WITH QUERY too and you end up with the rather more readable:
WITH inv AS (
SELECT ca.user_id AS userid
FROM shop_db.invoices AS inv
LEFT JOIN shop_db.carts AS ca ON ca.invoice_id = inv.id
LEFT JOIN shop_db.cart_items AS ci ON ci.cart_id = ca.id
WHERE (inv.created BETWEEN '2014-11-13' AND '2014-11-14' OR inv.created BETWEEN '2013-11-14' AND '2013-11-15')
AND inv.status <> 'do_not_book'
AND inv.id IS NOT NULL
), s3 AS (
SELECT u.user_id, min(cc.created) AS first_unlocked, bundle_article_code
FROM licensing_db.serial_numbers AS sn
LEFT JOIN licensing_db.licenses AS lic ON lic.id = sn.license_id
LEFT JOIN user_db.users AS u ON u.id = lic.user_id
LEFT JOIN licensing_db.challenge_codes AS cc ON cc.serial_number_id = sn.id
WHERE u.user_id IN (SELECT userid FROM inv)
GROUP BY u.user_id, bundle_article_code
HAVING bundle_article_code LIKE 'BuSu90%'
AND first_unlocked IS NOT NULL
)
SELECT userid, date_trunc('day', first_unlocked) AS "S9_Unlock"
FROM inv
LEFT JOIN s3 ON s3.user_id = inv.userid;
So the main query is now reduced to 3 lines and both the WITH-QUERY's perform a logically self-contained query of the database. The other sub-queries you refer to can similarly become a WITH-QUERY and then you assemble them in the main query. Remember that you can refer to earlier named queries in the list of with-queries, as is shown above with inv being referred to by s3. While such CTE's are syntactically not providing new functionality (except for the RECURSIVE variant), they do make complex queries much more readable and therefore easier to maintain.
Another approach would be to factor out logical sub-components (such as the inv sub-query) and make a VIEW out of those. Then you can simply reference the view in the main query. Making the whole thing a view is probably also a good idea if you want to make the query more flexible. What if you want to query for Suite9.1 ('BuSu91%') on 27 March 2014? Taken those literals out and then using them as WHERE clauses in a view makes your query more versatile; this can be either with sub-queries or with the complete CTE.
(Please check if the semantics are still right in the s3 with-query because without your table structures and sample data I ccannot test my code above.)
Instead of solving your problem as one big monolithic relational sql query, I would seriously consider going the "procedural" way, by using the built-in "plpgsql" language of postgresql. This could bring a lot of clarity in your application.
Trying to retrive the MAX doc in the right table.
SELECT F43.PDDOCO,
F43.PDSFXO,
F43.PDLNID,
F43.PDAREC/100 As Received,
F431.PRAREC/100,
max(F431.PRDOC)
FROM PRODDTA.F43121 F431
LEFT OUTER JOIN PRODDTA.F4311 F43
ON
F43.PDKCOO=F431.PRKCOO
AND F43.PDDOCO=F431.PRDOCO
AND F43.PDDCTO=F431.PRDCTO
AND F43.PDSFXO=F431.PRSFXO
AND F43.PDLNID=F431.PRLNID
WHERE F431.PRDOCO = 401531
and F431.PRMATC = 2
and F43.PDLNTY = 'DC'
Group by
F43.PDDOCO,
F43.PDSFXO,
F43.PDLNID,
F43.PDAREC,
F431.PRAREC/100
This query is still returning the two rows in the right table. Fairly new to SQL and struggling with the statement. Any help would be appreciated.
Without seeing your data it is difficult to tell where the problem might so I will offer a few suggestions that could help.
First, you are joining with a LEFT JOIN on the PRODDTA.F4311 but you have in the WHERE clause a filter for that table. You should move the F43.PDLNTY = 'DC' to the JOIN condition. This is causing the query to act like an INNER JOIN.
Second, you can try using a subquery to get the MAX(PRDOC) value. Then you can limit the columns that you are grouping on which could eliminate the duplicates. The query would them be similar to the following:
SELECT F43.PDDOCO,
F43.PDSFXO,
F43.PDLNID,
F43.PDAREC/100 As Received,
F431.PRAREC/100,
F431.PRDOC
FROM PRODDTA.F43121 F431
INNER JOIN
(
-- subquery to get the max
-- then group by the distinct columns
SELECT PDKCOO, max(PRDOC) MaxPRDOC
FROM PRODDTA.F43121
WHERE PRDOCO = 401531
and PRMATC = 2
GROUP BY PDKCOO
) f2
-- join the subquery result back to the PRODDTA.F43121 table
on F431.PRDOC = f2.MaxPRDOC
AND F431.PDKCOO = f2.PDKCOO
LEFT OUTER JOIN PRODDTA.F4311 F43
ON F43.PDKCOO=F431.PRKCOO
AND F43.PDDOCO=F431.PRDOCO
AND F43.PDDCTO=F431.PRDCTO
AND F43.PDSFXO=F431.PRSFXO
AND F43.PDLNID=F431.PRLNID
AND F43.PDLNTY = 'DC' -- move this filter to the join instead of the WHERE
WHERE F431.PRDOCO = 401531
and F431.PRMATC = 2
If you provide your table structures and some sample data, it will be easier to determine the issue.
I have a table (Cars) which saves some characteristics car like EngineNo, LastProductionStepId, NodyNo, ...
Besides, I have another table (CarSteps) which saves all steps that a specific car should pass during its manufacturing proccess like Engine Assigning(Id = 2), Engraving(3), PrePaint(4), Paint(5), AfterPaint(6), Confirmation(7), Delivery(8)
I would like to get all cars that are between PrePaint and Confirmation at the moment:
select cr.Id, cr.BodyNo, cr.LastStepId
from Cars cr WITH (NOLOCK)
inner join CarSteps steps WITH (NOLOCK) on cr.Id = trace.CarId and cr.LastStepId=trace.StepId
where
cr.LastStepId >= 4
AND cr.[Status] = 1
AND steps.[Status] = 1
AND not exists ( select *
from CarSteps steps1 WITH (NOLOCK)
where steps1.CarId = cr.Id
AND steps1.StepId >= 7 AND steps1.Status = 1
)
Because CarSteps has many records (44 million) the query is slow .
what is your opinion? is there any better way to get those cars?
Looking at your query I see a join from Cars to CarSteps, I see you joining to trace.CarId and trace.StepId is. trace is not defined in your query.
from
Cars cr WITH (NOLOCK) inner join
CarSteps steps WITH (NOLOCK) on
cr.Id = trace.CarId and
cr.LastStepId=trace.StepId
I may be able to help if i have better understand the fully query.
What does the execution plan reveal?
I have the following Linq statement:
(from order in Orders.AsEnumerable()
join component in Components.AsEnumerable()
on order.ORDER_ID equals component.ORDER_ID
join detail in Detailss.AsEnumerable()
on component.RESULT_ID equals detail.RESULT_ID
where orderRestrict.ORDER_MNEMONIC == "MyOrderText"
select new
{
Mnemonic = detail.TEST_MNEMONIC,
OrderID = component.ORDER_ID,
SeqNumber = component.SEQ_NUM
}).ToList()
I expect this to put out the following query:
select *
from Orders ord (NoLock)
join Component comp (NoLock)
on ord .ORDER_ID = comp.ORDER_ID
join Details detail (NoLock)
on comp.RESULT_TEST_NUM = detail .RESULT_TEST_NUM
where res.ORDER_MNEMONIC = 'MyOrderText'
but instead I get 3 seperate queries that select all rows from the tables. I am guessing that Linq is then filtering the values because I do get the correct values in the end.
The problem is that it takes WAY WAY too long because it is pulling down all the rows from all three tables.
Any ideas how I can fix that?
Remove the .AsEnumerable()s from the query as these are preventing the entire query being evaluated on the server.