AND OR SQL operator with multiple records - sql

I have the following query where if brand1/camp1 taken individually, query returns the correct value but if I specify more than one brand or campaigns, it returns some other number and I am not sure what the math is behind that. It is not the total of the two either.
I think it is IN operator that is specifying OR with "," as opposed to what I require it to do which is consider AND
select campaign,
sum(case when campaign in ('camp1', 'camp2') and description in ('brand1', 'brand2') then orders else 0 end) as brand_convs
from data.camp_results
where campaign in ('camp1', 'camp2') and channel='prog' and type='sbc'
group by campaign
having brand_convs > 0
order by brand_convs desc;
Any thoughts?

The problem is in the IN part as you suspected: The two IN operators do not affect eachother in any way, so campaign can be camp1 while description is brand2.
If your DBMS supports multiple columns in an IN statement, you use a single IN statement:
SELECT campaign, SUM(
CASE WHEN (campaign, description) IN (
('camp1', 'brand1'),
('camp2', 'brand2')
) THEN orders ELSE 0 END
) [rest of query...]
If not, you're probably going to have to use ANDs and ORs
SELECT campaign, SUM(
CASE WHEN
(campaign='camp1' AND description='brand1')
OR (campaign='camp2' AND description='brand2')
THEN orders ELSE 0 END
) [rest of query...]

Related

SQL query case when at least one

How to use CASE to show 'debtor' if at least one of the invoices is not paid (Invoice_Status = 1)?
*(A customer has multiple invoices)
Here's the query to show the an Id_Customer and the status of his multiple invoices, but this repeats the Id_Customer for each invoice he has
SELECT Id_Customer,
CASE Invoice_Status
WHEN 1 THEN 'Debtor'
ELSE 'No debts'
END AS Status
FROM Tb_Invoices
ORDER BY Id_Customer
GO
You need to use an aggregate (min, max, count etc) on Invoice_Status, then map that value via you case statement. You haven't told us about your schema or data so we can't really help you more than that. I.e. something like this:
SELECT CASE
WHEN count(Invoice_Status = 1) > 0 THEN 'Dector'
ELSE 'No debts'
END
FROM Tb_Invoices
ORDER BY Id_Customer

SQL Group by CASE result

I have a simple SQL query on IBM DB2. I'm trying to run something as below:
select case when a.custID = 42285 then 'Credit' when a.unitID <> '' then 'Sales' when a.unitID = '' then 'Refund'
else a.unitID end TYPE, sum(a.value) as Total from transactions a
group by a.custID, a.unitID
This query runs, however I have a problem with group by a.custID - I'd prefer not to have this, but the query won't run unless it's present. I'd want to run the group by function based on the result of the CASE function, not the condition pool behind it. So, I'm looking something like:
group by TYPE
However adding group by TYPE reports an error message "Column or global variable TYPE not found". Also removing a.custID from group section reports "Column custID or expression in SELECT list not valid"
Is this going to be possible at all or do I need to review my CASE function and avoid using the custID column since at the moment I'm getting a grouping also based on custID column, even though it's not present in SELECT.
I understand why the grouping works as it does, I'm just wondering if it's possible to get rid of the custID grouping, but still maintain it within CASE function.
If you want terseness of code, you could use a subquery here:
SELECT TYPE, SUM(value) AS Total
FROM
(
SELECT CASE WHEN a.custID = 42285 THEN 'Credit'
WHEN a.unitID <> '' THEN 'Sales'
WHEN a.unitID = '' THEN 'Refund'
ELSE a.unitID END TYPE,
value
FROM transactions a
) t
GROUP BY TYPE;
The alternative to this would be to just repeat the CASE expression in the GROUP BY clause, which is ugly, but should still work. Note that some databases (e.g. MySQL) have overloaded GROUP BY and do allow aliases to be used in at least some cases.

changing positions of sql query results

The title is not claryifying my problem but this is how i could describe it.
I have a query which returns the following result :
and i was wondering if there is a way to reduce the number of lines from three to one having all the three no null values ( 400, 1000 and 21820 in one line ) with banquet as description.
Thank you for reading.
PS: this is just a capture of a part of the query results and there are a lot of duplicated lines. i can post my query if it would be helpful. i'm using some select case there..
EDIT:
THANK YOU guys but i solved that by copying the results of the main query to input of another one and adding distinct and sum clauses
SELECT description, MAX(number1) AS number1, MAX(number2) AS number2)
FROM myTable
GROUP BY description
At last in Oracle, you can use "When"
Eg:
SELECT
DESCRIPTION,
CASE WHEN SUMPRICE1 IS NULL THEN
CASE WHEN SUMPRICE2 IS NULL THEN
CASE WHEN SUMPRICE3 IS NULL THEN
0
ELSE SUMPRICE3 END
ELSE SUMPRICE2 END
ELSE SUMPRICE1 END AS SUMPRICE
FROM MY_TABLE
GROUP BY DESCRIPTION, SUMPRICE
Off course this is useble just if you have a static number of columns.
EDIT: I think I don't get the problem, but, if you don't want to merge the columns, you can use:
SELECT DESCRIPTION,
MAX(SUMPRICE1) AS SUMPRICE1,
MAX(SUMPRICE2) AS SUMPRICE2,
MAX(SUMPRICEN) AS SUMPRICEN
FROM MY_TABLE
GROUP BY DESCRIPTION
Or you can use the case to avoid the null, in the case of any of rows don't have a value:
SELECT DESCRIPTION,
CASE WHEN MAX(SUMPRICE1) IS NULL THEN 0 ELSE WHEN MAX(SUMPRICE1) END AS SUMPRICE1,
CASE WHEN MAX(SUMPRICE2) IS NULL THEN 0 ELSE WHEN MAX(SUMPRICE2) END AS SUMPRICE2,
CASE WHEN MAX(SUMPRICEN) IS NULL THEN 0 ELSE WHEN MAX(SUMPRICEN) END AS SUMPRICEN
FROM MY_TABLE
GROUP BY DESCRIPTION

conditional select between multiple fields

I have a table with a certain flag called FL_virtual, if this flag equals 1 i need to get my stock in a special way using a function
now i want to make a select statement with it but depending on this flag i need to adjust my select to use a certain function instead of a subquery
so presume i start with this select statement
select product_name,..(other options from the product table),
(select sum(qy_stock) from STOCK where warehouse_id = 1) as 'qy_stock_internal',
(select sum(qy_stock) from STOCK where warehouse_id = 2) as qy_stock_external
From product
now i need to change the subquery (qy_stock) with a call to a function when the fl_virtual flag is 1
so that it becomes like this
select product_name,..(other options from the product table),
FN_GET_stock_PRODUCT(1) as qy_stock_internal,
FN_GET_stock_PRODUCT(2) as qy_stock_external
from product
so i thought a simple if then else structure will do but for some reason i can't get it to work
this is how i thought it would look
select product_name,..(other options from the product table),
IF fl_virtual > 0 THEN
(select sum(qy_stock) from STOCK where warehouse_id = 1) as 'qy_stock_internal',
(select sum(qy_stock) from STOCK where warehouse_id = 2) as qy_stock_external
ELSE
FN_GET_stock_PRODUCT(1) as qy_stock_internal,
FN_GET_stock_PRODUCT(2) as qy_stock_external
END IF
but it doesn't work , anyone got an idea?
You're close - just use CASE instead of IF (you have to repeat your condition, since you cannot easily return two columns from a single CASE (see P.S.):
select product_name,
..(other options from the product table),
(CASE
WHEN fl_virtual > 0 THEN
(select sum(qy_stock) from STOCK where warehouse_id = 1)
ELSE
FN_GET_stock_PRODUCT(1)
END) as qy_stock_internal,
(CASE
WHEN fl_virtual > 0 THEN
(select sum(qy_stock) from STOCK where warehouse_id = 2)
ELSE
FN_GET_stock_PRODUCT(2)
END) as qy_stock_external
P.S.: It is possible to return multiple values from a single CASE, e.g. using Object Types, but that's stuff for a different question :-)
Best way is to use a union select with those 2 different queries and contitions.
Btw. the names stock and warehouse look like a typical school work examin.

multiple count(distinct)

I get an error unless I remove one of the count(distinct ...). Can someone tell me why and how to fix it?
I'm in vfp. iif([condition],[if true],[else]) is equivalent to case when
SELECT * FROM dpgift where !nocalc AND rectype = "G" AND sol = "EM112" INTO CURSOR cGift
SELECT
list_code,
count(distinct iif(language != 'F' AND renew = '0' AND type = 'IN',donor,0)) as d_Count_E_New_Indiv,
count(distinct iif(language = 'F' AND renew = '0' AND type = 'IN',donor,0)) as d_Count_F_New_Indiv /*it works if i remove this*/
FROM cGift gift
LEFT JOIN
(select didnumb, language, type from dp) d
on cast(gift.donor as i) = cast(d.didnumb as i)
GROUP BY list_code
ORDER by list_code
edit:
apparently, you can't use multiple distinct commands on the same level. Any way around this?
VFP does NOT support two "DISTINCT" clauses in the same query... PERIOD... I've even tested on a simple table of my own, DIRECTLY from within VFP such as
select count( distinct Col1 ) as Cnt1, count( distinct col2 ) as Cnt2 from MyTable
causes a crash. I don't know why you are trying to do DISTINCT as you are just testing a condition... I more accurately appears you just want a COUNT of entries per each category of criteria instead of actually DISTINCT
Because you are not "alias.field" referencing your columns in your query, I don't know which column is the basis of what. However, to help handle your DISTINCT, and it appears you are running from WITHIN a VFP app as you are using the "INTO CURSOR" clause (which would not be associated with any OleDB .net development), I would pre-query and group those criteria, something like...
select list_code,
donor,
max( iif( language != 'F' and renew = '0' and type = 'IN', 1, 0 )) as EQualified,
max( iif( language = 'F' and renew = '0' and type = 'IN', 1, 0 )) as FQualified
from
list_code
group by
list_code,
donor
into
cursor cGroupedByDonor
so the above will ONLY get a count of 1 per donor per list code, no matter how many records that qualify. In addition, if one record as an "F" and another does NOT, then you'll have a value of 1 in EACH of the columns... Then you can do something like...
select
list_code,
sum( EQualified ) as DistEQualified,
sum( FQualified ) as DistFQualified
from
cGroupedByDonor
group by
list_code
into
cursor cDistinctByListCode
then run from that...
You can try using either another derived table or two to do the calculations you need, or using projections (queries in the field list). Without seeing the schema, it's hard to know which one will work for you.