How to Sum two columns meeting certain conditions - sum

What I want to do is basically merge the two highlighted code, so that the end result is it using this SUM formula for only the items matching the LIKE criteria (under WHERE) - so that I am still able to pull GameDescriptions that do not include the LIKE criteria. Hope that makes sense... enter image description here

I think you just need to replace that part of the WHERE statement with a case statement in the SUM, like this:
SELECT
SUM(CASE WHEN GameDescription LIKE '5R25L%' THEN NetRevenue
ELSE 0 END) / COUNT(DISTINCT AccountingDate)
AS 'ES Created TheoWPU'
FROM Prime.dbo.PivotData

Related

Why does a CASE WHEN give me a different result to a WHERE with the same condition?

I'm trying to use a case when and a pivot to filter some data, but get a result of a total count of 0, however, when I use the same condition in a where statement I get a result that's more what i expected.
SELECT * FROM(SELECT FYEAR,
CASE WHEN (DIAG_3_01 IN ('E10','E11','E12','E13','E14','O24') OR DIAG_4_01 IN ('E232','N251','P702')) AND (OPERTN_3_01 IN ('N26','P22','X07','X09','X10','X11') OR OPERTN_4_01 IN ('Q011','X215','X216','X273','X121')) THEN 'a'
ELSE 'Other' END AS 'Procs',
(FCE)
FROM database
) AS a
PIVOT(COUNT(FCE) FOR [Procs] IN ([a])) AS p;
So this results in a table with column name a and a row value of 0, whereas this code results in a total of about 4000:
SELECT COUNT(FCE)
FROM database
WHERE (DIAG_3_01 IN ('E10','E11','E12','E13','E14','O24') OR DIAG_4_01 IN ('E232','N251','P702')) AND (OPERTN_3_01 IN ('N26','P22','X07','X09','X10','X11') OR OPERTN_4_01 IN ('Q011','X215','X216','X273','X121'));
Unfortunately I cant share the database contents, but would appreciate any insight as to why this might be happening.
The CASE statement is like an If-statement, which only returns the very first value it founds that meets the criteria. You can also check multiple cases with WHEN and if no criteria are met, then the query will show whatever is in the ELSE statement.
The WHERE clause is just filtering the result, meaning it tell the query which records should not be ignored.

Combining multiple Case statements into single output column

I need to re-categorise a column marketing_channel with 10 unique values into 15 distinct groups by matching certain criteria.
I've done this via case statements but then the output is in 15 new columns.
Is there a more elegant way to re-class the marketing_channel by simply adding 1 extra column like "marketing_sub_channel" that contains all new 15 classes?
Is there better way to do the classification than by creating 15 case statements? Was thinking a with clause, but that would also be quite lengthy
Output looks like this but ultimately just a single added column would be great:
Yes you just have to change the format a bit. Remove the "case" statement at the beginning of each line and just put the "End" at the end of the statement, like so :
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
WHEN conditionN THEN resultN
ELSE null
END as marketing_sub_channel
or in your case:
CASE
WHEN medium like ('%affiliate%') or marketing_cannel ='Affiliates' then 'Affiliate'
WHEN campaign like ('%_Display brand_global Progromatic Display%') then 'Dispay'
WHEN campaign like ('%display%') and campaign not like ('progrommatic') then 'Dispay'
....
else null
END as marketing_sub_channel
Also I would like to note that in your case statement since you have '%display%' and '%_Display brand_global Progromatic Display%' that you place the longer more specific one on top so it can trigger if it needs to. If '%display%' is on top then it will always trigger first since it contains a substring of the other one.

Rails/SQL - How to filter by distinct value in a group

I'm working in Rails, but an answer in SQL is equally helpful. Let's say I have a table of Users and a table of Purchases. I want to find the Users who have only ever bought Item A. I was hoping to use a query along the lines of:
User.joins(:purchases).group(:id).having("DISTINCT(item) = 'A'").pluck(:id)
This is a simplification of the question I need to answer, but this grouping issue is my main roadblock. For that reason, I'm hoping for an answer that is logically very similar, as other workarounds would likely not apply.
Does this work in Rails?
User.joins(:purchases).group(:id).having("MIN(item) = MAX(item) AND MIN(item) = 'A'").pluck(:id)
This phrase as: there is only one distinct value (since MIN() and MAX() are equal), that is 'A'.
Alternatively:
having("MAX(CASE WHEN item <> 'A' THEN 1 ELSE 0 END) = 0")
Which would stand for: no other value than 'A'.
In having you can use only aggregate functions (e.g. having count(id) > 2) or expressions on columns you did the grouping on e.g. having("id > 1").
So depending on your db you may try to find an aggregate function that identifies existence of item in the grouping per id.
For PostgreSql that would be something like (haven't tested):
...
GROUP BY id
HAVING 'A' = ANY(ARRAY_AGG(item))

Return NULL instead of 0 when using COUNT(column) SQL Server

I have query which running fine and its doing two types of work, COUNT and SUM.
Something like
select
id,
Count (contracts) as countcontracts,
count(something1),
count(something1),
count(something1),
sum(cost) as sumCost
from
table
group by
id
My problem is: if there is no contract for a given ID, it will return 0 for COUNT and Null for SUM. I want to see null instead of 0
I was thinking about case when Count (contracts) = 0 then null else Count (contracts) end but I don't want to do it this way because I have more than 12 count positions in query and its prepossessing big amount of records so I think it may slow down query performance.
Is there any other ways to replace 0 with NULL?
Try this:
select NULLIF ( Count(something) , 0)
Here are three methods:
1. (case when count(contracts) > 0 then count(contracts) end) as countcontracts
2. sum(case when contracts is not null then 1 end) as countcontracts
3. nullif(count(contracts), 0)
All three of these require writing more complicated expressions. However, this really isn't that difficult. Just copy the line multiple times, and change the name of the variable on each one. Or, take the current query, put it into a spreadsheet and use spreadsheet functions to make the transformation. Then copy the function down. (Spreadsheets are really good code generators for repeated lines of code.)

Writing a query to include certain values but exclude others when looking for a latest time period

I am trying to write a query that looks for a people that have a certain code with the latest period (year) but not if they have another code with that latest period(year). I'll be explicit just so my example makes sense.
I want people who have the code A1,A2,A3,A4,A5 but not AG,AP,AQ. There are people who have an A1 code for a period (like 2014) and an AG code for a the same period. I'd like to exclude them. Not everyone has a code so the field value could be NULL.
Is there a way to express this in a different way (i.e. less characters) than the way I did?
SELECT
people.firstName
FROM
people
WHERE EXISTS (
SELECT *
FROM codes
WHERE
codes.people_id = people.id
AND period = (SELECT MAX(period) FROM codes codes2 WHERE codes2.people_id = codes.people_id)
AND code LIKE 'A[1-5]'
)
AND NOT EXISTS (
SELECT *
FROM codes
WHERE
codes.people_id = people.id
AND period = (
SELECT MAX(period)
FROM codes codes2
WHERE codes2.people_id = codes.people_id
)
AND code LIKE 'A[GPQ]'
)
Schema is as follows:
People
id (PK)
firstName
Codes
people_id (FK) many to one relation with People table
code (e.g. "A1", "A2", "AG")
period (e.g. "2013", "2014")
There are so many ways you could do that, I'm not an SQL expert but I can't see your query being too bad, if you want to try and reduce the number of sub-queries you could consider using the GROUP BY clause along with a SUM Aggregate function in a HAVING clause.
I started updating your code as follows:
SELECT
people.firstName
FROM
people
LEFT JOIN codes AS a15 ON a15.people_id = people.id AND a15.code LIKE 'A[1-5]'
LEFT JOIN codes AS agpq ON agpq.people_id = people.id AND agpq.code LIKE 'A[GPQ]'
GROUP BY
people.firstName
HAVING
SUM(CASE WHEN a15.code IS NULL THEN 0 ELSE 1 END) > 0
AND SUM(CASE WHEN agpq.code IS NULL THEN 0 ELSE 1 END) = 0
This however doesn't take into account anything to do with period specific requirements described. You could add the period to the GROUP BY clause or add it to a WHERE or one of the JOIN constraints but I'm not quite sure from your description exactly what you're after (I don't believe this is through any fault of your own, I just can't personally align the code provided to the description).
I would also like to point out that the SUM functions above will not give an accurate count of the number of matching codes. This is because if both A[GPQ] and A[1_5] return at least one row, the number returned by each constraint will be multiplied by the number returned for the other, it can however be used to determine if there are "any" returned items as if the criteria is matched it will have a SUM(...) > 0
I'm sure a more experienced SQL Developer / DBA will be able to poke many holes in my proposed query but it might give them or someone else something to work from and hopefully gives you ideas for alternatives to using sub-queries.