How to convert SQL statement to equivalent Cognos query calc? - sql

I was building a crosstab like so:
and need to instead convert into a list. The part that's giving me trouble is converting the grouping of v_IT or BU which feeds down into Act and Direct Cost into 4 separate fields for the list which would be 'IT Act', 'IT Direct Cost', 'BU Act', and BU Direct Cost.' I'm not sure how to make a calculation for these fields using those two data items.
I think the SQL would be something like:
Select Act$ from 'mytable' where v_ITorBU = 'IT'
for the first 'IT Act' data item at least.
v_IT or BU has two values 'IT', and 'BU'.
I tried
Case
When v_ITorBU = 'IT'
then act$
end
but this only gives me the overall act values, not those specifically for IT.
I need the specific IT actuals as well as the BU actuals.
Does anyone have any insight on how to make this into Cognos query calculations?

The grouping of v_IT or BU which feeds down into Act and Direct Cost into 4 separate fields for the list which would be 'IT Act', 'IT Direct Cost', 'BU Act', and BU Direct Cost.
Go to the query
add data items from the tool box
Create the definition expression, for example this would be for [IT Act]
IF( [v_IT or BU] = 'IT Act' )Then([Act$])Else(0)
Repeat this process for
IT Direct Cost
BU Act
BU Direct Cost
Also repeat these 4 data items for the cost metric
Remember to check the properties in order to achieve the correct aggregation

Here is the SQL.
select [Budget Category]
, [v_Cost Cat Consolidation]
, sum(case when [v_IT or BU] = 'IT'
then [Act $]
else 0
end) as 'IT Act'
, sum(case when [v_IT or BU] = 'IT'
then [Direct Cost]
else 0
end) as 'IT Direct Cost'
, sum(case when [v_IT or BU] = 'BU'
then [Act $]
else 0
end) as 'BU Act'
, sum(case when [v_IT or BU] = 'BU'
then [Direct Cost]
else 0
end) as 'BU Direct Cost'
from MyTable
where {somefilters}
group by [Budget Category]
, [v_Cost Cat Consolidation]
So a data item expression in Cognos may look like ...
case
when [v_IT or BU] = 'IT'
then [Act $]
else 0
end
...and you'll want to be sure to use the Total aggregate function on it.
If you have done that and the numbers are not looking right, please add some detail to the problem statement.
This can also be done using the IF-THEN-ELSE methodology proposed by hnoel.

Related

Joined tables returning correct value when selecting single row but incorrect when entire dataset

I have 3 tables which I have joined: campaign level, ad level, and keyword level, and I need certain things from each of these. All 3 contain the following identical columns: campaign_name, campaign_id, day. Two of them also contain 'ad_group_name'.
The query is functioning and returning all the right values for data coming from keyword and campaign, but the values I need from ad level (conversion_name and it's values) are not. But the confusing part for me is that when I use the 'WHERE' clause and select only one row, the values are correct and match up to the source tables. Additionally, the values of a.conversion_name add up to 'conversion' total (+/- 1/2).
Results from single row (WHERE clause)
When I remove the WHERE clause and select the entire table, my numbers are significantly larger than they should be. The a.conversion_name values no longer add up to the 'conversion' total - in fact sometimes conversions = 0, and the a.conversion_name values return values.
Results when selecting entire table
Results when selecting entire table 2
I think I understand why this is happening, it's a grouping issue (?), and I have searched through lots of the existing threads, tried out sub queries and DISTINCTS, but my skill level at the moment means I am really struggling to figure this out.
Should I change how things are grouped? I have also tried adding the a.conversion_name as a dimension and then selecting it, but this doesn't help either.
WITH raw AS (SELECT
k.day,
k.campaign_name,
k.ad_group_name,
k.ad_group_type,
k.ad_group_id,
k.campaign_id,
k.keyword,
k.keyword_match_type,
AVG(CASE WHEN a.conversion_name = 'Verification Submitted' THEN a.conversions END) AS conv_verification_submitted,
AVG(CASE WHEN a.conversion_name = 'Email Confirmed' THEN a.conversions END) AS conv_email_confirmed,
AVG(CASE WHEN a.conversion_name = 'Account created' THEN a.conversions END) AS conv_account_created,
AVG(CASE WHEN a.conversion_name = 'Verification Started' THEN a.conversions END) AS conv_verification_started,
AVG(CASE WHEN a.conversion_name = 'Deposit Succeeded' THEN a.conversions END) AS conv_deposit_succeeded,
AVG(CASE WHEN a.conversion_name = 'Trade Completed' THEN a.conversions END) AS conv_trade_completed,
AVG(K.clicks) as clicks,
AVG(K.conversions) as conversions,
AVG(K.costs) as spend,
AVG(K.impressions) as impressions,
AVG(k.quality_score) as quality_score,
AVG(c.search_impression_share) as search_impression_share,
AVG(k.search_exact_match_impression_share) as search_exact_match_impression_share,
AVG(c.search_lost_impression_share_rank) as search_lost_impression_share_rank,
AVG(c.search_top_impression_share) as search_top_impression_share,
AVG(c.search_lost_impression_share_budget) as search_lost_impression_share_budget,
FROM `bigqpr.keyword-level-data` as k
LEFT JOIN `bigqpr.campaign-level-data` as c
ON c.campaign_name = k.campaign_name and c.day = k.day
LEFT JOIN `bigqpr.ad-level-data` as a
ON a.campaign_name = k.campaign_name and a.day = k.day and a.ad_group_name = k.ad_group_name
group by 1,2,3,4,5,6,7,8,a.conversion_name)
SELECT
day,
campaign_name,
ad_group_name,
ad_group_type,
ad_group_id,
campaign_id,
keyword,
keyword_match_type,
AVG(conv_verification_submitted) as conv_verification_submitted,
AVG(conv_email_confirmed) as conv_email_confirmed,
AVG(conv_account_created) as conv_account_created,
AVG(conv_verification_started) as conv_verification_started,
AVG(conv_deposit_succeeded) as conv_deposit_succeeded,
AVG(conv_trade_completed) as conv_trade_completed,
AVG(clicks) as clicks,
AVG(conversions) as conversions,
AVG(spend) as spend,
AVG(impressions) as impressions,
AVG(quality_score) as quality_score,
AVG(search_impression_share) as search_impression_share,
AVG(search_exact_match_impression_share) as search_exact_match_impression_share,
AVG(search_lost_impression_share_rank) as search_lost_impression_share_rank,
AVG(search_top_impression_share) as search_top_impression_share,
AVG(search_lost_impression_share_budget) as search_lost_impression_share_budget,
FROM raw
WHERE keyword = "specifickeyword" and day = "2022-05-22" and ad_group_name = "specificadgroup"
GROUP BY 1,2,3,4,5,6,7,8
I am also a beginner, but my first thought is to try an Inner Join instead of a Left Join. Sometimes this helps my result sets fit the number I'm looking for instead of being so large.

How to add results of previous columns (SQL)

I am not sure if it is even possible in SQL, will appreciate your response.
I create 4 Case statements to define quantity of sold items (of a specific type).
After that, I want to create another 5th column where I can take an overall sold amount and subtract all those 4 specific types.
I am trying to understand how it can be done in one SQL query. The SUM and division should be done on a row level.
In other words, trying to understand how I can SUM 4 case statements and divide that sum from another column and it all should be in one column.
I hope my explanation makes sense.
p/s I use SQL specifically SSMS.
You've only provided a query fragment so the answer is only a query fragment.
You cannot reference column aliases created in the same level, you can however create your query as a derived table or a CTE, and then the columns are available to the outer query, thus
with t as (
select
p.PDQSLD,
p.[PDITM#] as [Item Number],
Sum(PDQSLD) as [Quantity Sold],
p.PDWEDT as [Week Ending Date],
l.SGDWHS as [Default Ship Warehouse],
p.PDCHN as [Chain Code],
case when p.PDCHN = 'DH' then p.PDQSLD else 0 end as DHSLD,
case when p.PDCHN = 'WM' then p.PDQSLD else 0 end as WMSLD,
case when p.PDCHN = 'MJ' then p.PDQSLD else 0 end as MJSLD,
case when p.PDCHN = 'BJ' then p.PDQSLD else 0 end as BJSLD
from ...
)
select t.*,
PDQSLD - ( DHSLD + WMSLD + MJSLD + BJSLD ) as OTHRSLD
from t
Note that in T-SQL, 'quoted' values are for string literals, if you need to delimit column aliases, use [square brackets].

Count Distinct Not Working in Case Select Oracle SQL

I have a SQL question in which the code fails to count distinct ID's.  It does count them, but does not do so distinctly. I have provided a small snippet of code below and have bolded the issue.
SELECT
"RESERVATION_STAT_DAILY"."RESORT" AS "RESORT",
"RESERVATION_STAT_DAILY"."BUSINESS_DATE" AS "BUSINESS_DATE",
to_char("RESERVATION_STAT_DAILY"."BUSINESS_DATE",'MON-yyyy') AS "MONTHYEAR",
Extract(day from "RESERVATION_STAT_DAILY"."BUSINESS_DATE") AS "DAY",
Extract(month from "RESERVATION_STAT_DAILY"."BUSINESS_DATE") AS "MONTH",
Extract(year from "RESERVATION_STAT_DAILY"."BUSINESS_DATE") AS "YEAR",
"RESERVATION_STAT_DAILY"."SOURCE_CODE" AS "SOURCE_CODE",
"RESERVATION_STAT_DAILY"."MARKET_CODE" AS "MARKET_CODE",
"RESERVATION_STAT_DAILY"."RATE_CODE" AS "RATE_CODE",
"RESERVATION_STAT_DAILY"."RESV_NAME_ID" AS "RESV_NAME_ID",
(CASE WHEN "RESERVATION_STAT_DAILY"."SOURCE_CODE" = 'GDS'
AND "RESERVATION_STAT_DAILY"."RATE_CODE" NOT IN ('BKIT', 'EXPEDIA')
AND "RESERVATION_STAT_DAILY"."MARKET_CODE" NOT IN ('GOVG', 'ENT')
THEN 'GDS'
ELSE 'Other'
END) AS "BizUnit",
COUNT(DISTINCT CASE WHEN "RESERVATION_STAT_DAILY"."SOURCE_CODE" = 'GDS'
AND "RESERVATION_STAT_DAILY"."RATE_CODE" NOT IN ('BKIT', 'EXPEDIA')
AND "RESERVATION_STAT_DAILY"."MARKET_CODE" NOT IN ('GOVG', 'ENT')
THEN "RESERVATION_STAT_DAILY"."RESV_NAME_ID"
ELSE NULL
END) AS "COST",
(SUM("RESERVATION_STAT_DAILY"."BUSINESS_DATE" - "RESERVATION_STAT_DAILY"."BUSINESS_DATE_CREATED")/(COUNT ("RESERVATION_STAT_DAILY"."BUSINESS_DATE_CREATED"))) AS "DIFF",
SUM(NVL("RESERVATION_STAT_DAILY"."NIGHTS",0)) AS "NIGHTS",
SUM(NVL("RESERVATION_STAT_DAILY"."ROOM_REVENUE",0)) AS "ROOM_REVENUE"
FROM "OPERA"."RESERVATION_STAT_DAILY" "RESERVATION_STAT_DAILY"
Where RESORT in ('558339','558341','4856','558340','602836','HCA','HZSD', 'TAC') and
BUSINESS_DATE < SYSDATE AND EXTRACT(year FROM "RESERVATION_STAT_DAILY"."BUSINESS_DATE_CREATED") >=2016
GROUP BY
"RESERVATION_STAT_DAILY"."RESORT",
"RESERVATION_STAT_DAILY"."BUSINESS_DATE",
to_char("RESERVATION_STAT_DAILY"."BUSINESS_DATE",'MON-yyyy'),
Extract(day from "RESERVATION_STAT_DAILY"."BUSINESS_DATE"),
Extract(month from "RESERVATION_STAT_DAILY"."BUSINESS_DATE"),
Extract(year from "RESERVATION_STAT_DAILY"."BUSINESS_DATE"),
"RESERVATION_STAT_DAILY"."SOURCE_CODE",
"RESERVATION_STAT_DAILY"."MARKET_CODE",
"RESERVATION_STAT_DAILY"."RATE_CODE",
"RESERVATION_STAT_DAILY"."RESV_NAME_ID",
( CASE
WHEN (("RESERVATION_STAT_DAILY"."SOURCE_CODE" = 'GDS') AND ("RESERVATION_STAT_DAILY"."RATE_CODE" != 'BKIT' OR "RESERVATION_STAT_DAILY"."RATE_CODE" != 'EXPEDIA'
)) THEN 'GDS'
ELSE 'Other'
END )
Some general tips to clean up your code, plus a solution:
As others have said, NOT IN clauses would be perfect here. Substitute them for those huge blocks of != comparisons. You also want your COUNT and SUM functions to be outside the CASE statements, as shown below.
SELECT
...
CASE WHEN "RESERVATION_STAT_DAILY"."SOURCE_CODE" = 'GDS'
AND "RESERVATION_STAT_DAILY"."RATE_CODE" NOT IN ('BKIT', 'EXPEDIA', ...)
AND "RESERVATION_STAT_DAILY"."MARKET_CODE" NOT IN ('GOVG', 'ENT', ...)
THEN 'GDS'
ELSE 'Other'
END AS "BizUnit",
COUNT(DISTINCT CASE WHEN "RESERVATION_STAT_DAILY"."SOURCE_CODE" = 'GDS'
AND "RESERVATION_STAT_DAILY"."RATE_CODE" NOT IN ('BKIT', 'EXPEDIA', ...)
AND "RESERVATION_STAT_DAILY"."MARKET_CODE" NOT IN ('GOVG', 'ENT', ...)
THEN "RESERVATION_STAT_DAILY"."RESV_NAME_ID"
ELSE NULL
END) AS "COST",
...
FROM
"OPERA"."RESERVATION_STAT_DAILY" "RESERVATION_STAT_DAILY"
WHERE
...
GROUP BY
...
Your code was over 570 lines long. Some people consider 1/10 of that to be too much code. Notice how I snipped out the parts that aren't directly applicable to your issue? This is how you go about creating a minimal, complete, and verifiable working example.
Just a few remarks (too long for a comment):
AND ("RESERVATION_STAT_DAILY"."RATE_CODE" != 'BKIT' OR "RESERVATION_STAT_DAILY"."RATE_CODE" != 'EXPEDIA' )? Think about that for a moment. When is that condition not met? The rate code will always be different from either one value or the other (usually both), except for NULL, where the result is "unknown".
THEN COUNT(DISTINCT "RESERVATION_STAT_DAILY"."RESV_NAME_ID") ELSE COUNT(DISTINCT "RESERVATION_STAT_DAILY"."RESV_NAME_ID") END) AS "COST". So in any case you count distinct RESV_NAME_ID. Why the CASE then?
As you group by RESV_NAME_ID, COUNT(DISTINCT "RESERVATION_STAT_DAILY"."RESV_NAME_ID") can always only be 1 in a group.
sum(NVL("RESERVATION_STAT_DAILY"."NIGHTS",0)) and sum(NVL("RESERVATION_STAT_DAILY"."ROOM_REVENUE",0)): SUM ignores nulls, so you don't have to make these zeros before adding them up. A sum, hoever, can be null, so you may want NVL(SUM(NIGHTS), 0) instead.
As to readablity: queries in all upper caps are hard to read. Either use lower case or mix the two (e.g. upper case for SQL keywords). As no column contains blanks or the like, you don't need quotes. As only one table is involved, you don't need a table qualifier. And if you did, you should have a short alias name for the table and use this instead of the whole name. And you should format the query with indentation, so we see the clauses (FROM, GROUP BY etc.) on first glance.

Converting SQL pivot table to T-SQL for Report Builder 3.0

I've been having a spot of bother importing a rather long-winded SQL pivot table dataset into SQL Server Report Builder 3.0 in a format which allows me to add parameter to the report outcome. I understand that this requires the query to be T-SQL friendly
The context is, in case it helps, is that i'm building a report to give a view over various market research panel's eligibility statuses, and i'd like to be able to present a drop down menu to let users flick between panels. So the end #parameter will be on PanelCode / PanelName. It's a composite query:
SELECT
ELT.PanelCode,
ELR.PanelName,
ELR.Year,
ELT.PeriodType,
ELT.PeriodValue,
ELT.TotalPanelists,
ELT.EligiblePanelists,
ELR.TotalEligible,
ELR.TotalVacation,
ELR.TotalExcused,
ELR.TotalInactive,
ELR.TotalConnection,
ELR.TotalCompliance
FROM --the Ineligibility Reason Pivot Table (ELR)
(SELECT
PanelCode,
PanelName,
Year,
PeriodType,
PeriodValue,
Max([Eligible]) as TotalEligible,
Max([Vacation]) as TotalVacation,
Max([Excuse]) as TotalExcused,
Max([Inactive]) as TotalInactive,
Max([Connection]) as TotalConnection,
Max([Compliance]) as TotalCompliance
FROM
(SELECT
PanelCode,
PanelName,
Year,
PeriodType,
PeriodValue,
EligibilityFailureReason,
FROM FullPanellistEligibilityView) FPR
Pivot
(count(EligibilityFailureReason) FOR EligibilityFailureReason IN ([Eligible], [Vacation], [Excuse], [Inactive], [Connection], [Compliance])) AS PVT
WHERE PeriodType <> '4 week period' and Year > 2012
GROUP BY PanelCode, PanelName, PeriodType, Year, PeriodValue) as ELR
, -- And the Eligibility Totals Query, ELT
(
SELECT
PanelCode,
PanelName,
Year,
PeriodType,
PeriodValue,
Count(Poll1s) as TotalPanelists,
Sum(Poll1s) as EligiblePanelists
FROM
(SELECT
PanelCode,
PanelName,
Year
PeriodType,
PeriodValue,
CAST(isEligible as INT) as Poll1s
FROM FullPanellistEligibilityView) FPR
GROUP BY PanelCode, PeriodType, PeriodValue) ELT
WHERE (ELT.PeriodValue=ELR.PeriodValue) and (ELT.PanelCode=ELR.PanelCode)
I've been really struggling to find resources online which suggest how to take larger queries and make them Parameter-able in Report Builder 3. What do I need to add in addition to WHERE PanelName = #PanelName to make this run?
EDIT1: I don't doubt that I've made this query far more complicated than necessary, i'm self-teaching. The schema isn't really necessary as all this data is pulled from one single, already existing view, FullPanellistEligibilityView, sample data, stripped down and mocked up from the view, can be found here
There are two things you need to do in order to set up a data driven parameter selection.
Firstly, you need to create a dataset to populate your parameter drop down menu. This needs to list all the values you want your user to be able to select, in the correct order. This can return a column each for the Label shown to the user and the value passed to the query:
select distinct PanelCode -- Parameter Value
,PanelName -- Parameter Label
from FullPanellistEligibilityView
order by PanelName
Create a Parameter and set the available values to this dataset, with the appropriate column used for the Label and Value properties.
Secondly, you need to add a filter to your dataset. I have taken the liberty of re-writing your query above to use a derived table/common table expression/cte instead of your PIVOT. The code below includes the reference to the SSRS parameter which will insert the 'Value' for the parameter once selected. This code is obviously not tested as I don't have your schema, but the design should be easy enough to understand:
with t
as
(
select PanelCode
,PeriodValue
,count(isEligible) as TotalPanelists -- I'm assuming this is a BIT column, in which case it shouldn't have any null values. If it does, you will need to handle this with count(isnull(isEligible,0))
,Sum(CAST(isEligible as INT)) as EligiblePanelists
from FullPanellistEligibilityView
where PanelCode = #PanelCode -- This will filter your data due to the INNER JOIN below.
group by PanelCode
,PeriodType
,PeriodValue
)
select e.PanelCode
,e.PanelName
,e.Year
,e.PeriodType
,e.PeriodValue
,t.TotalPanelists
,t.EligiblePanelists
,sum(case when e.EligibilityFailureReason = 'Eligible' then 1 else 0 end) as TotalEligible,
,sum(case when e.EligibilityFailureReason = 'Vacation' then 1 else 0 end) as TotalVacation,
,sum(case when e.EligibilityFailureReason = 'Excuse' then 1 else 0 end) as TotalExcused,
,sum(case when e.EligibilityFailureReason = 'Inactive' then 1 else 0 end) as TotalInactive,
,sum(case when e.EligibilityFailureReason = 'Connection' then 1 else 0 end) as TotalConnection,
,sum(case when e.EligibilityFailureReason = 'Compliance' then 1 else 0 end) as TotalCompliance
from FullPanellistEligibilityView e
inner join t
on(e.PanelCode = t.PanelValue
and e.PeriodValue = t.PeriodValue
)
where e.PeriodType <> '4 week period'
and e.Year > 2012
group by e.PanelCode
,e.PanelName
,e.Year
,e.PeriodType
,e.PeriodValue
,t.TotalPanelists
,t.EligiblePanelists

Conditional SUM not returning any value

Writing an SQL query to get a device count out of spiceworks.
I need to get the device type, the model, how many are in use and how many are unassigned.
Currently anything thats unassigned is marked as decommissioned.
So I have the following query
SELECT `device_type` AS "Device",
`model` AS "Model",
SUM (CASE WHEN `user_tag` NOT LIKE "%decommissioned%" THEN 1 ELSE 0 END) AS "Assigned",
SUM (CASE WHEN `user_tag` LIKE "%decommissioned%" THEN 1 ELSE 0 END) AS "Avail."
FROM `devices`
WHERE `auto_tag` LIKE "%LA2%" OR `user_tag` LIKE "%LA2%" OR `location` LIKE "%LA2%"
Group by `device_type`, `model`​
EG: if marked as decommissioned count as 1 toward available, otherwise count as 1 toward assigned.
My current problem is that the Second SUM opperation is returning no data. Not even a 0.
Im sure its something simple that im missing.
Thanks in advance for the help.
It came down to SpiceWorks choking on the formatting of the query.
the back ticks were removed from around column names, double quotes replaced with single quotes.
Works as expected.
Thank you all for your assistance.
SELECT
device_type
, model
, COUNT(CASE WHEN user_tag NOT LIKE '%decommissioned%' THEN 1 ELSE NULL END) as 'Assigned'
, COUNT(CASE WHEN user_tag LIKE '%decommissioned%' THEN 1 ELSE NULL END) as 'Avail'
, COUNT(*) as 'TotalItems'
FROM devices
WHERE auto_tag LIKE '%LA2%' OR user_tag LIKE '%LA2%' OR location LIKE '%LA2%'
GROUP BY model, device_type
ORDER BY location DESC, device_type ASC​