best query for a complex situation - sql

I have a table with following columns,(id,fkid, flag1,flag2,flag3,flag4). The possible value for each flag field is -1 to 3 and null is allowed. What I need is a query to check if count of any flag field with value 2 is greater than 3 for a given foreign key fkid. The way I am doing is write a query for each field. It works but very not smart to me. Anyone has better idea? Thanks.

You can do this with one query:
select fkid
from t
group by fkid
having sum(case when flag1 = 2 then 1 else 0 end) > 3 or
sum(case when flag2 = 2 then 1 else 0 end) > 3 or
sum(case when flag3 = 2 then 1 else 0 end) > 3 or
sum(case when flag4 = 2 then 1 else 0 end) > 3
I do agree strongly with the comments, though, that sample data, sample results, and a clear table structure would greatly improve the question.

Query below will also answer your question, sql fiddle example: http://sqlfiddle.com/#!3/adda9/2
SELECT
DISTINCT fkid
FROM
tblTest pvt
UNPIVOT
(
FlagValue FOR Flag IN
(flag1,flag2,flag3,flag4)
) as Unpvt
WHERE
FlagValue = 2
GROUP BY
FKID, FLAG
HAVING COUNT(*)>3

Related

SQL query to fetch the result set with same status

The table 1 is as follows,
ID
FK1_ID
FK2_ID
1
1
1
2
1
2
3
1
3
The table with FK2 is as follows,
ID
Type
Status
1
Type1
True
2
Type2
True
3
Type1
False
The FK2_ID column is the ID column of table 2.
The expected result is, for any FK1_ID(which I have as a list of IDs), need to check all its FK2 entries in the 2nd table of Type1 and status True.
For example:
Here, I want to return YES, if all the Type1 entries are True for the specific FK1_ID. Else NO.
So, for FK1_ID with 1, the FK2 table has 3 records. Of which Type1 has 2 records. I should return YES, if both Type1 records are True, else NO.
I want accomplish this using SQL.
Any help is appreciated?
Looks like you just need to compare a conditional count of Status to the full count, with a CASE for the final result.
SELECT
t1.FK1_ID,
Result = CASE WHEN COUNT(*) = COUNT(CASE WHEN FK2.Status = 'True' THEN 1 END)
THEN 'Yes'
ELSE 'No' END
FROM table1 t1
JOIN FK2 ON FK2.ID = t1.FK2_ID
AND FK2.Type = 'Type1'
GROUP BY
t1.FK1_ID;
A slightly shorter but less understandable version
CASE WHEN COUNT(*) = COUNT(NULLIF(FK2.Status, 'False'))
Alternatively
CASE WHEN COUNT(NULLIF(FK2.Status, 'True')) = 0
I'm not totally following your logic (how these two tables are joined) but sounds like you want to compare a total count with a conditional count so maybe something like
with t as (select type, count(status) as cnt,
sum(case when status ='True' then 1 else 0 end) as truecnt
from FK2
group by type)
select type, case when truecnt > 0 and cnt = truecnt then 'Yes' else 'No' end as MyResult
from t

SQL/PL Rows to Columns using max query with Sub-query

I was using max function to convert from rows to column and before using it in sub-query, it works well.
Situation: [Please refer to the picture as hyperlinked] I have a total of three questions for customer to answer and their responses will be extracted from the database. However, for the first question, customer is allowed to choose from 1 - 10. 10 refers to free text and will be stored in answer for Question = 2.
However, I would like to exclude free text input from the customer and for the extraction to be in column. Having to say that I will be having three columns: Response_1, Response_2 and Response_3. When customer choose 10 for Question = 1, the answer for Question = 3 will be stored in Response_2 while answer for Question = 4 in Response_3.
My attempt is as follow:
select customer_ID
max( CASE WHEN Question = 1 THEN Answer END) Response_1,
max( CASE WHEN Question = 1 AND Answer != 10 THEN
( select
max( CASE WHEN Question = 2 THEN Answer END)
from t_question_answer)
ELSE
( select
max( CASE WHEN Question = 3 THEN Answer END)
from t_question_answer)
END)
) Response_2
from t_question_answer
group by customer_ID
The result went wrong when it comes to the data extracted for customer_2 where I think in the sub-query, it looks for the maximum value in the whole data again instead of specifying the same customer.
You need more conditional logic in your conditional aggregation:
select customer_ID
max(CASE WHEN Question = 1 THEN Answer END) Response_1,
(case when max(case when question = 1 and answer = 10 then 1 else 0 end) > 0
then max( CASE WHEN Question = 3 THEN Answer END)
else max( CASE WHEN Question = 2 THEN Answer END)
end) as Response_2,
(case when max(case when question = 1 and answer = 10 then 1 else 0 end) > 0
then max( CASE WHEN Question = 4 THEN Answer END)
else max( CASE WHEN Question = 3 THEN Answer END)
end) as Response_3
from t_question_answer
group by customer_ID

What does a multiple count query in SQL return?

I have a product table and every product might be delivered, idle, shipping, preparing.
I want to show a list with the counts of products for each state, and I can see how to query for that here:
How to get multiple counts with one SQL query?
However, what does this query return, and how do I assign the return value to lets say, 4 integers, called deliveredCount, idleCount, shippingCount, preparingCount?
PS: For the record, I am using SQLite with OrmLite in Android with JAVA
EDIT: In this SO question people explain what Query to do when you want to get multiple counts, but they don't tell us what does that query return and in what format. For example:
SELECT a.distributor_id,
(SELECT COUNT(*) FROM myTable WHERE level='personal' and distributor_id = a.distributor_id) as PersonalCount,
(SELECT COUNT(*) FROM myTable WHERE level='exec' and distributor_id = a.distributor_id) as ExecCount,
(SELECT COUNT(*) FROM myTable WHERE distributor_id = a.distributor_id) as TotalCount
FROM myTable a ;
What is the return type of this and what is the format?
PS2: Someone was really quick to downvote my question because it lacked sufficient information. Then I edited it, but the downvote still remains :(
Hard to say for sure but sounds like you need to use a version of the top answer in the link you have provided.
Something like;
SELECT ProductID,
COUNT(*) AS Total,
SUM(CASE WHEN pStatus = 'delivered' THEN 1 ELSE 0 END) DeliveredCount,
SUM(CASE WHEN pStatus = 'idle' THEN 1 ELSE 0 END) IdleCount,
SUM(CASE WHEN pStatus = 'shipping' THEN 1 ELSE 0 END) ShippingCount,
SUM(CASE WHEN pStatus = 'preparing' THEN 1 ELSE 0 END) PreparingCount
FROM ProductTable
GROUP BY ProductID
This will return something like;
ProductID | DeliveredCount | IdleCount | ...
1 | 250 | 3250 | ...
You might want to try this.
SELECT
SUM(CASE WHEN Prod = 'delivered' THEN 1 ELSE 0 END) as deliveredCount,
SUM(CASE WHEN Prod = 'idle' THEN 1 ELSE 0 END) as idleCount,
SUM(CASE WHEN Prod = 'shipping' THEN 1 ELSE 0 END) as shippingCount,
SUM(CASE WHEN Prod = 'preparing' THEN 1 ELSE 0 END) as preparingCount
FROM Product
select
concat(state, "Count"),
count(*)
from product
group by state
Which would return 4 rows (assuming four unique values of state):
fooCount | 15
etc

SQL Count with multiple conditions then join

Quick one,
I have a table, with the following structure
id lid taken
1 1 0
1 1 0
1 1 1
1 1 1
1 2 1
Pretty simply so far right?
I need to query the taken/available from the lid of 1, which should return
taken available
2 2
I know I can simply do two counts and join them, but is there a more proficient way of doing this rather than two separate queries?
I was looking at the following type of format, but I can not for the life of me get it executed in SQL...
SELECT
COUNT(case taken=1) AS taken,
COUNT(case taken=0) AS available FROM table
WHERE
lid=1
Thank you SO much.
You can do this:
SELECT taken, COUNT(*) AS count
FROM table
WHERE lid = 1
GROUP BY taken
This will return two rows:
taken count
0 2
1 2
Each count corresponds to how many times that particular taken value was seen.
Your query is correct just needs juggling a bit:
SELECT
SUM(case taken WHEN 1 THEN 1 ELSE 0 END) AS taken,
SUM(case taken WHEN 1 THEN 0 ELSE 1 END) AS available FROM table
WHERE
lid=1
Alternatively you could do:
SELECT
SUM(taken) AS taken,
COUNT(id) - SUM(taken) AS available
FROM table
WHERE
lid=1
SELECT
SUM(case WHEN taken=1 THEN 1 ELSE 0 END) AS taken,
SUM(case WHEN taken=0 THEN 1 ELSE 0 END) AS available
FROM table
WHERE lid=1
Weird application of CTE's:
WITH lid AS (
SELECT DISTINCT lid FROM taken
)
, tak AS (
SELECT lid,taken , COUNT(*) AS cnt
FROM taken t0
GROUP BY lid,taken
)
SELECT l.lid
, COALESCE(a0.cnt, 0) AS available
, COALESCE(a1.cnt, 0) AS taken
FROM lid l
LEFT JOIN tak a0 ON a0.lid=l.lid AND a0.taken = 0
LEFT JOIN tak a1 ON a1.lid=l.lid AND a1.taken = 1
WHERE l.lid=1
;

Get the distinct count of values from a table with multiple where clauses

My table structure is this
id last_mod_dt nr is_u is_rog is_ror is_unv
1 x uuid1 1 1 1 0
2 y uuid1 1 0 1 1
3 z uuid2 1 1 1 1
I want the count of rows with:
is_ror=1 or is_rog =1
is_u=1
is_unv=1
All in a single query. Is it possible?
The problem I am facing is that there can be same values for nr as is the case in the table above.
Case statments provide mondo flexibility...
SELECT
sum(case
when is_ror = 1 or is_rog = 1 then 1
else 0
end) FirstCount
,sum(case
when is_u = 1 then 1
else 0
end) SecondCount
,sum(case
when is_unv = 1 then 1
else 0
end) ThirdCount
from MyTable
you can use union to get multiple results e.g.
select count(*) from table with is_ror=1 or is_rog =1
union
select count(*) from table with is_u=1
union
select count(*) from table with is_unv=1
Then the result set will contain three rows each with one of the counts.
Sounds pretty simple if "all in a single query" does not disqualify subselects;
SELECT
(SELECT COUNT(DISTINCT nr) FROM table1 WHERE is_ror=1 OR is_rog=1) cnt_ror_reg,
(SELECT COUNT(DISTINCT nr) FROM table1 WHERE is_u=1) cnt_u,
(SELECT COUNT(DISTINCT nr) FROM table1 WHERE is_unv=1) cnt_unv;
how about something like
SELECT
SUM(IF(is_u > 0 AND is_rog > 0, 1, 0)) AS count_something,
...
from table
group by nr
I think it will do the trick
I am of course not sure what you want exactly, but I believe you can use the logic to produce your desired result.