SQL query inside another query? - sql

I have this table:
total
user
wallet
storagesummary
chain
40
user1
wallet1
2
1
30
user1
wallet1
4
1
8
user1
wallet2
1
1
2
user2
wallet3
3
1
41
user2
wallet3
4
3
And this is what I'm trying to accomplish:
Type1, Type2, n... columns are a combination of storagesummary and chain
Just for the sake of example: if storagesummary == 2 and chain == 1, then it's gonna be Type1.
I tried something like this, but I don't think it's the best approach and I dunno what to do with the user/wallet columns:
SELECT (SELECT total from MyTable where storagesummary = 2 and chain == 1) as Total Type1 Count,
(SELECT total from MyTable where storagesummary = 4 and chain == 1) as Total Type2 Count,
.......
I cant' figure out how to achieve this.

This could use a bit of conditional aggregation to pivot that.
SELECT
CONCAT(t.user, ' / ', t.wallet) AS "User Wallet Address"
, SUM(CASE
WHEN t.storagesummary = 2 AND t.chain = 1
THEN t.total
ELSE 0
END) AS "Total Type1"
, SUM(CASE
WHEN t.storagesummary = 4 AND t.chain = 3
THEN t.total
WHEN t.storagesummary = 1 AND t.chain = 1
THEN t.total
ELSE 0
END) AS "Total Type2"
, SUM(CASE
WHEN t.storagesummary IN(2,5) AND t.chain >= 2
THEN t.total
ELSE 0
END) AS "Total Type3"
FROM MyTable t
GROUP BY t.user, t.wallet
ORDER BY t.user, t.wallet
Not sure if you need SUM or MAX though.
And the logic in the CASE's will needs corrections.
But if you get the concept, then you'll understand what to change.

I think what you are missing is matching internal column names with outer select, for example:
select action_id, next_action_id from ( select action_id, lead(action_id) over (order by action_id) next_action_id from action) where action_id <> next_action_id-1;
that's for oracle db, but normal SQL can fit without next/lead thing.

Related

CASE WHEN PARTITION BY - Returning Value for Groups with Two Specific Values in Same Column Across Group

As the title says, I'm having trouble returning groups that have two specific values across the group in the same column.
Here is an example of the data:
Claim | Exposure | Product
1 1 B
1 2 C
2 1 B
2 2 D
My goal is essentially create a third column that specifies if a Claim has a Product = B for any of it's exposures and a Product = C for any of it's exposures (i.e. "All required present"). If the claim is missing an exposure with a specific product, I want to return something like "Product C missing."
Ideally it would result in the following:
Claim | Exposure | Product | RequiredCheck
1 1 B All Required
1 2 C All Required
2 1 B Missing C
2 2 D Missing C
I've tried to use a GROUP BY Claim HAVING Product = B and Product = C, but this isn't working because the check is based on the same column across a group of claims, and I don't necessarily want to limit my results to only those with "All Required" values.
I've also try to use a MAX(CASE WHEN Product = B and Product = C THEN 1 ELSE 0 END) PARTITION BY Claim) but that also wouldn't return any results because the check is based on a value in the same column.
I have thought about coding the products to be a specific number (i.e A = 1, B = 2) and then using SUM OVER PARTITION BY, but this also won't work because I could have a claim with multiple exposures with the same product and I can't just say where the count > 5 because it could have 5 exposures with the product A.
Any help is appreciated!
Use case with window functions:
select t.*,
(case when num_b > 0 and num_c > 0 then 'All required'
when num_b > 0 then 'C missing'
when num_c > 0 then 'B missing'
else 'Both missing'
end) as requiredcheck
from (select t.*,
sum(case when product = 'B' then 1 else 0 end) over (partition by claim) as num_b,
sum(case when product = 'C' then 1 else 0 end) over (partition by claim) as num_c
from t
) t;

SQL find total count of each type in a column

I'm learning SQL and am stumped on what should be a simple query. I have a table with the following pattern:
Id | Type
------------
1 | Red
2 | Blue
3 | Blue
4 | Red
..
I would like to write a query to return a table that counts the total number of instances of each type and returns a table with the following pattern, for example, if 'Blue' occurs in 12 rows, and 'Red' occurs in 16 rows in the table above, the result would be:
Blue | Red
-----------
12 | 16
You could do it this way:
SELECT Type, COUNT(*) FROM TABLE GROUP BY Type
If you'd like to see the Types in separate columns, you could do this:
SELECT SUM(CASE WHEN Type = 'Blue' THEN 1 ELSE 0 END) AS Blue, SUM(CASE WHEN Type = 'Red' THEN 1 ELSE 0 END) AS Red FROM TABLE
I suggest using count over partition by. Here's a code I wrote to help my company check for duplicate Technician EmployeeID's and Pincodes, including count and YES/NO columns to allow filtering in excel so they can see what corrections need to be made:
select
t.TechnicianId, t.TechnicianName, t.Pincode, t.EmployeeID
, [Pincode Count] = count(t.Pincode) over (partition by t.Pincode)
, [Duplicate Pincode?] = case count(t.Pincode) over (partition by t.Pincode) when 1 then 'NO' else 'YES' end
, [EmployeeID Count] = count(t.EmployeeID) over (partition by t.EmployeeID)
, [Duplicate EmployeeID?] = case count(t.EmployeeID) over (partition by t.EmployeeID) when 1 then 'NO' else 'YES' end
from Technicians t
group by t.TechnicianId, t.TechnicianName, t.Pincode, t.EmployeeID
order by 4

SQL get all IDs where Sub-IDs are exactly specified without getting other IDs where some Sub-ID's are not present

Sorry for that title, I don't know how to describe my problem in one sentence.
I have Table like this:
event | thema
-------------
1 1
1 2
2 1
2 2
2 3
3 1
3 2
3 3
3 4
4 1
4 2
4 3
What I want are the event IDs where the thema is exaclty 1, 2 and 3, not the event ID where it is only 1 and 2 or 1,2,3 and 4.
SELECT event WHERE thema=1 OR thema=2 OR thema=3
returns them all
SELECT event WHERE thema=1 AND thema=2 AND thema=3
returns nothing.
I think this should be absolutely simple, but stack is overflown...
Thanks for some help!
Group by the event and take only those having at least one thema 1 and 2 and 3 and not any other
SELECT event
from your_table
group by event
having sum(case when thema = 1 then 1 else 0 end) > 0
and sum(case when thema = 2 then 1 else 0 end) > 0
and sum(case when thema = 3 then 1 else 0 end) > 0
and sum(case when thema not in (1,2,3) then 1 else 0 end) = 0
This type of query is a "set-within-sets" query (your are looking for sets of "thema" for each event). The most general approach is aggregation using a having clause. This might be the shortest way to write the query using standard SQL:
select event
from table t
group by event
having count(distinct (case when thema in (1, 2, 3) then thema end)) = 3;
or,
first create table #themas (depending on vendor, make this a temp table or a simple table-valued variable) that contains user-specified list of thema values, then
Select event from your_table y
Where not exists
(Select * From #Themas t
where Not Exists
(Select * From your_table
where event = y.event
and thema = t.thema))
and not exists (Select * From your_table
where event = t.event
and thema not in
(Select thema From #Themas ))

SQL QUERY MERGE TWO ROW DATA

Suppose My Database is like this :
MemberName MemberID ResultsEligibilityID
Thuso 2 1
Thuso 2 1
Maubane 3 2
Maubane 3 1
CDeveloper 5 2
CDeveloper 5 2
Now is it possible to write a query to display (The Below output) based on this:
if both ResultsEligibilityID for a single Member is 1 then Eligibile,
Otherwise Non-Eligible.
OUTPUT
MemberName MemberID ResultsEligibilityID Results
Thuso 2 1 Eligible
Maubane 3 2 Non-Eligible
CDeveloper 5 2 Non-Eligible
Thanks in advance for the help.
Please try:
select
MemberName,
MemberID,
MAX(ResultsEligibilityID) ResultsEligibilityID ,
(case when sum(case when ResultsEligibilityID=1 then 1 else 0 end)= COUNT(*)
then 'Eligible' else 'Non-Eligible' end) Results
From
YourTable
group by MemberName,MemberID

Semi-complicated result set in sql query

I have a user table like this
FIRSTNAME | LASTNAME | ID |
--------------------------------
James | Hay | 1 |
Other | Person | 2 |
I also have an attendance table like this
EVENTID | USERID | ATTENDANCE | STATUS |
-----------------------------------------------
1 1 True 3
2 1 False 1
3 1 False 3
1 2 False 1
2 2 True 3
3 2 True 3
Basically, when a user is invited to an event, a row is added to the attendance table which has the event ID, their user ID, false attendance, and status 0.
Status is just an indicator of their response
0 = No Response
1 = Said No
2 = Said Yes
3 = Said yes and seats confirmed
My end result I want to get from querying these two tables is quite complicated and I can't figure out what I need to do.
I want to get a result like this
NAME | % of saying YES to an RSVP | % of attending after saying yes
-------------------------------------------------------------------------------
James Hay | 66 | 50
Other Person | 66 | 100
I'm sure you can work out how I got those numbers but to explain, James Hay had the 3 (yes) status to 2/3 events invited to. So % of saying yes is 66. Out of the 2 he said yes to, he only attended 1/2 so % of attending after saying yes is 50%
Any push in the right track would be much appreciated here since I can't get my head around this.
EDIT:
Also something quite important is that I want the results to include every user in the database even if they have 0 rows in the attendance table.
select
u.firstname, u.lastname
-- said yes, as percentage
,floor(100.0
* count(case when a.status in (2,3) then 1 end)
/ count(u.id)) yes
-- attended after saying yes, as percentage
,floor(100.0
* count(case when a.status in (2,3) and attendance='true' then 1 end)
/ nullif(count(case when a.status in (2,3) then 1 end),0)) attendance
--,count(u.id) rsvp -- total invites
from users u
left join attendance a on a.userid = u.id
group by u.firstname, u.lastname
Note: For the special case where the user has never received an invite, the statistics show as 0% and NULL.
Explanation of the terms:
count(case when a.status in (2,3) then 1 end)
represents how many times they said yes, used twice
count(u.id)
how many invites (recorded in attendance) received. Special case is when they have received none, in which case the LEFT JOIN makes it 1 (not important)
count(case when a.status in (2,3) and attendance='true' then 1 end)
count of how many times they attended, AFTER having said yes
SELECT A.NAME,B.PERCENTAGE_YES_RSVP,B.PERCENTAGE_AFTER_YES
FROM
(
SELECT U.ID AS ID,U.FIRSTNAME+''+U.LASTNAME AS NAME
FROM USERS U
) A,
(
SELECT A.USERID,A.PERCENTAGE_YES_RSVP,B.PERCENTAGE_AFTER_YES
FROM
(
SELECT B.USERID,ROUND((CAST(B.COUNT_YES_RSVP AS FLOAT)/B.TOTAL_COUNT)*100,0) AS PERCENTAGE_YES_RSVP
FROM
(SELECT A.USERID,
SUM(CASE WHEN A.STATUS=3 THEN 1 END)AS COUNT_YES_RSVP,
COUNT(*) AS TOTAL_COUNT
FROM ATTENDANCE A
GROUP BY A.USERID
) B
) A,
(
SELECT C.USERID,(CAST(C.COUNT_AFTER_YES_RSVP AS FLOAT)/C.TOTAL_COUNT)*100 AS PERCENTAGE_AFTER_YES
FROM
(SELECT A.USERID,
SUM(CASE WHEN A.STATUS=3 AND A.ATTENDANCE='TRUE' THEN 1 END)AS COUNT_AFTER_YES_RSVP,
SUM(CASE WHEN A.STATUS=3 THEN 1 END) AS TOTAL_COUNT
FROM ATTENDANCE A
GROUP BY A.USERID
) C
)B
WHERE A.USERID=B.USERID
) B
WHERE A.ID = B.USERID;
Edit:
Whoops, forgot to join on users :)
select firstname, lastname,
convert(decimal (5, 2), 1. * count(case when status in (2, 3) then 1 end) / count(*) * 100) SaidYes,
convert(decimal (5, 2), 1. * count(case when status in (2, 3) and attendance = 'True' then 1 end) / count(case when status in (2, 3) then 1 end) * 100) ActuallyAttended
from attendance a
join users u on a.userid = u.id
group by firstname, lastname