GROUP BY CLAUSE USE - sql

I have a table with different payment method types: CHECK, MONEY ORDER, CASH. I need to show the break down of different payment types, following is my query. Could anyone suggest or comment how to do it optimally.
select
COUNT(T3.PAY_METHOD),
T1.CLAIM_ID
from TB1 T3
JOIN TB2 T2 ON T3.CLAIM_ID = T2.CLAIM_ID
GROUP BY T3.PAYMENT_METHOD_CD
Following is output column should look
|CHECK|MONEY ORDER|CASHIER'S CHECK|CASH|CREDIT CARD|
Displays the total count of all payments received via CHECK that were applied to the specific LIABLE INDIVIDUAL.

If you really need the output as columns, then you will want to use a SUM(case when method = '' then 0 else 1 end) type solution. Like this.
select t1.claim_id,
sum(case when t3.pay_method = 'CASH' then 1 else 0 end) as "CASH",
sum(case when t3.pay_method = 'MONEY ORDER' then 1 else 0 end) as "MONEY ORDER",
sum(case when t3.pay_method = 'CHECK' then 1 else 0 end) as "CHECK",
T1.CLAIM_ID
from TB1 T3
JOIN TB2 T2 ON T3.CLAIM_ID = T2.CLAIM_ID
GROUP BY T1.CLAIM_ID
But it would be much simpler if you just want them each as rows.
select T1.CLAIM_ID, T3.PAY_METHOD, COUNT(*)
from TB1 T3
JOIN TB2 T2 ON T3.CLAIM_ID = T2.CLAIM_ID
GROUP BY T1.CLAIM_ID, T3.PAY_METHOD

sql would be:
select T3.PAY_METHOD
, COUNT(T3.PAY_METHOD) records
from TB1 T3
JOIN TB2 T2 ON T3.CLAIM_ID = T2.CLAIM_ID
GROUP BY T3.PAY_METHOD
You can use application code to format the output.

Related

How to avoid `missing expression` error in sql

I'd like to count number of each product by following sql
but I suffered following error..
ORA-00936: Missing Expression
Where is wrong with my sql.
If someone has opinion,please let me know.
Thanks
select t.customer,
count(case when left(t.product,2)='AD' then 1 end) as A,
count(case when left(t.product,1)='F' then 1 end) as B,
count(case when left(t.product,1)='H' then 1 end) as C,
from table t
left join table2 t2
on t.customer = t2.customer
where t2.type='VLI'
group by t.customer
Oracle doesn't have LEFT() function while MySQL does, use SUBSTR() instead. And remove the comma, which's typo , at the end of the fourth line
SELECT t.customer,
COUNT(CASE
WHEN SUBSTR(t.product, 1, 2) = 'AD' THEN
1
END) AS A,
COUNT(CASE
WHEN SUBSTR(t.product, 1, 1) = 'F' THEN
1
END) AS B,
COUNT(CASE
WHEN SUBSTR(t.product, 1, 1) = 'H' THEN
1
END) AS C
FROM yourtable t
LEFT JOIN table2 t2
ON t.customer = t2.customer
WHERE t2.type = 'VLI'
GROUP BY t.customer
You have extra comma in row count(case when left(t.product,1)='H' then 1 end) as C,.
Delete the last comma and this error will go away.
I would suggest LIKE:
select t.customer,
sum(case when t.product like 'AD%' then 1 else 0 end) as A,
sum(case when t.product like 'F%' then 1 else 0 end) as B,
sum(case when t.product like 'H%' then 1 else 0 end) as C
from table t left join
table2 t2
on t.customer = t2.customer and t2.type='VLI'
group by t.customer;
Notes:
With like, you don't have to worry about an argument to a substring function matching the length of the matched string. I learned about the issues of inconsistencies there a long, long, long time ago.
I prefer sum() in this case over count(), but that is mostly aesthetic.
You are using a left join, but filtering in the where clause. This turns the join into an inner join. Either change the join to inner join or move the condition to the on clause (as this does).

PIVOT combined tables with criteria in sql

I have 2 tables
I want to show the result that returns all rows that has both a work and a home number
RESULT
I have written this SQL but it shows all. How do I show only to appear those with both values in home and work number and not showing the null values. I have tried adding WHERE PHONE_NUM IS NOT NULL but it did not work. I would appreciate any help. Thanks.
WITH TABLE1 AS (
SELECT
P.ID,
P.NAMES,
P.DIGIT,
Q.NUM_TYP,
Q.PHONE_NUM
FROM
dbo.TABLE1 P
INNER JOIN dbo.TABLE2 Q
ON P.ID = Q.ID
)
SELECT *
FROM
TABLE1
PIVOT (Max(PHONE_NUM) FOR NUM_TYP IN (HOME, WORK)) R
;
You can get the results from just table 2 using conditional aggregation:
select t2.id,
max(case when t2.num_type = 'HOME' then phone_num end) as home,
max(case when t2.num_type = 'WORK' then phone_num end) as work
from dbo.TABLE2 t2
group by t2.id
having max(case when t2.num_type = 'HOME' then phone_num end) is not null and
max(case when t2.num_type = 'WORK' then phone_num end) is not null;
You can join table 1 to get other fields if you like.

Aggregating SQL results, two tables, then summarizing results

Using MSSQL
I have a table of users, and a table of products to which they are subscribed. Those subscriptions are either Free (F) or Paid (P). I have joined the tables, converted the F/P value to numeric using a case statement, and then summed up those values by user ID, the idea being that anyone with only free accounts will have a sum of 0, those with at least one paid account a value 1 or greater. I've gotten this far with the following:
SELECT t1.user_id, SUM(
CASE
WHEN t2.free_paid = 'P'
THEN 1
ELSE 0
END ) as highest
FROM users t1 INNER JOIN accounts t2
ON t1.user_id = t2.user_id
WHERE t2.account = 'A'
GROUP BY t1.user_id
ORDER BY t1.user_id
This yields a result like:
755 2
1259 2
2031 1
3888 0
Meaning that all but 3888 have at least one paid account.
But now I would like to simply add those up somehow to get our two values, one a count of users with at least one paid account (3 in example), and a count of those with only free accounts (1 in example).
I tried declare two variables, e.g. #free and #paid and using a case statement to add to those values by wrapping that around the above and treating it as a subquery, but I am unable to get that run.
Any ideas?
Re-using the query from the question you can create a CTE (or a subquery) and aggregate the results:
;WITH CTE_UserAccounts AS (
SELECT t1.user_id, SUM(
CASE
WHEN t2.free_paid = 'P'
THEN 1
ELSE 0
END ) as highest
FROM users t1 INNER JOIN accounts t2
ON t1.user_id = t2.user_id
WHERE t2.account = 'A'
GROUP BY t1.user_id
)
SELECT
COUNT(CASE WHEN highest > 0 THEN 1 END) AS [Paid],
COUNT(CASE WHEN highest = 0 THEN 1 END) AS [Free]
FROM
CTE_UserAccounts;
SELECT
COUNT(DISTINCT CASE WHEN t2.free_paid = 'P' THEN t1.user_id END) as atleast_one_paid,
COUNT(DISTINCT CASE WHEN t2.free_paid <> 'P' THEN t1.user_id END) as onlyfree
FROM users t1
INNER JOIN accounts t2 ON t1.user_id = t2.user_id
WHERE t2.account = 'A'
You could just wrap around your original query and sum it up
SELECT SUM (case when highest > 0 THEN 1 else 0 END) as UsersWithPaidAccount,
SUM (case when highest = 0 THEN 1 else 0 END) as UsersWithOnlyFreeAccount
FROM (SELECT t1.user_id, SUM(
CASE
WHEN t2.free_paid = 'P'
THEN 1
ELSE 0
END ) as highest
FROM users t1 INNER JOIN accounts t2
ON t1.user_id = t2.user_id
WHERE t2.account = 'A'
GROUP BY t1.user_id)
as DerivedTable

SQL JOIN WITH TWO WHERE CLAUSES

I would like to implement the following SQL query : suppose using JOIN clause, due to now it's running quite slow:
SELECT ID_USER, NICK
FROM TABLE1
WHERE ID_USER IN
(
SELECT ID_INDEX1
FROM TABLE2
WHERE ID_INDEX2 = '2'
)
AND ID_USER NOT IN
(
SELECT ID_INDEX2
FROM TABLE2
WHERE ID_INDEX1 = '2' AND GO ='NO'
)
ORDER BY NICK ASC
You could do the "including" part with INNER JOIN and the "excluding" part with a "LEFT JOIN" + filtering:
SELECT DISTINCT t1.ID_USER, t1.NICK
FROM TABLE1 t1
INNER JOIN TABLE2 t2IN
ON t1.ID_USER = t2IN.ID_INDEX1
AND t2IN.ID_INDEX2 = '2'
LEFT JOIN TABLE2 t2OUT
ON t1.ID_USER = t2OUT.ID_INDEX2
AND t2OUT.ID_INDEX1 = '2'
AND t2OUT.GO = 'NO'
WHERE t2OUT.ID_INDEX IS NULL
ORDER BY t1.NICK ASC
Assuming that you want to filter by ID_INDEX1 in both cases (see my comment on your question), you can:
count the number of rows per user in table2 with value = 2
count the number of rows per user in table2 with value = 2 and go = 'NO'
return only those for which the first count is greater than 0 and the second count equals 0
i.e.:
select * from (
select
id_user,
nick,
sum(case when table2.id_index2 = '2' then 1 else 0 end) as count2_overall,
sum(case when table2.id_index2 = '2' and go = 'NO' then 1 else 0 end) as count2_no
from table1
join table2 on table1.id_user = table2.id_index1
group by id_user, nick
)
where count2_overall > 0 and count2_no = 0

grouping records in one temp table

I have a table where one column has duplicate records but other columns are distinct. so something like this
Code SubCode version status
1234 D1 1 A
1234 D1 0 P
1234 DA 1 A
1234 DB 1 P
5678 BB 1 A
5678 BB 0 P
5678 BP 1 A
5678 BJ 1 A
0987 HH 1 A
So in the above table. subcode and Version are unique values whereas Code is repeated. I want to transfer records from the above table into a temporary table. Only records I would like to transfer are where ALL the subcodes for a code have status of 'A' and I want them in the temp table only once.
So from example above. the temporary table should only have
5678 and 0987 since all the subcodes relative to 5678 have status of 'A' and all subcodes for 0987 (it only has one) have status of A. 1234 is ommited because its subcode 'DB' has status of 'P'
I'd appreciate any help!
Here's my solution
SELECT Code
FROM
(
SELECT
Code,
COUNT(SubCode) as SubCodeCount
SUM(CASE WHEN ACount > 0 THEN 1 ELSE 0 END)
as SubCodeCountWithA
FROM
(
SELECT
Code,
SubCode,
SUM(CASE WHEN Status = 'A' THEN 1 ELSE 0 END)
as ACount
FROM CodeTable
GROUP BY Code, SubCode
) sub
GROUP BY Code
) sub2
WHERE SubCodeCountWithA = SubCodeCount
Let's break it down from the inside out.
SELECT
Code,
SubCode,
SUM(CASE WHEN Status = 'A' THEN 1 ELSE 0 END)
as ACount
FROM CodeTable
GROUP BY Code, SubCode
Group up the codes and subcodes (Each row is a distinct pairing of Code and Subcode). See how many A's occured in each pairing.
SELECT
Code,
COUNT(SubCode) as SubCodeCount
SUM(CASE WHEN ACount > 0 THEN 1 ELSE 0 END)
as SubCodeCountWithA
FROM
--previous
GROUP BY Code
Regroup those pairings by Code (now each row is a Code) and count how many subcodes there are, and how many subcodes had an A.
SELECT Code
FROM
--previous
WHERE SubCodeCountWithA = SubCodeCount
Emit those codes with have the same number of subcodes as subcodes with A's.
It's a little unclear as to whether or not the version column comes into play. For example, do you only want to consider rows with the largest version or if ANY subcde has an "A" should it count. Take 5678, BB for example, where version 1 has an "A" and version 0 has a "B". Is 5678 included because at least one of subcode BB has an "A" or is it because version 1 has an "A".
The following code assumes that you want all codes where every subcode has at least one "A" regardless of the version.
SELECT
T1.code,
T1.subcode,
T1.version,
T1.status
FROM
MyTable T1
WHERE
(
SELECT COUNT(DISTINCT subcode)
FROM MyTable T2
WHERE T2.code = T1.code
) =
(
SELECT COUNT(DISTINCT subcode)
FROM MyTable T3
WHERE T3.code = T1.code AND T3.status = 'A'
)
Performance may be abysmal if your table is large. I'll try to come up with a query that is likely to have better performance since this was off the top of my head.
Also, if you explain the full extent of your problem maybe we can find a way to get rid of that temp table... ;)
Here are two more possible methods. Still a lot of subqueries, but they look like they will perform better than the method above. They are both very similar, although the second one here had a better query plan in my DB. Of course, with limited data and no indexing that's not a great test. You should try all of the methods out and see which is best for your database.
SELECT
T1.code,
T1.subcode,
T1.version,
T1.status
FROM
MyTable T1
WHERE
EXISTS
(
SELECT *
FROM MyTable T2
WHERE T2.code = T1.code
AND T2.status = 'A'
) AND
NOT EXISTS
(
SELECT *
FROM MyTable T3
LEFT OUTER JOIN MyTable T4 ON
T4.code = T3.code AND
T4.subcode = T3.subcode AND
T4.status = 'A'
WHERE T3.code = T1.code
AND T3.status <> 'A'
AND T4.code IS NULL
)
SELECT
T1.code,
T1.subcode,
T1.version,
T1.status
FROM
MyTable T1
WHERE
EXISTS
(
SELECT *
FROM MyTable T2
WHERE T2.code = T1.code
AND T2.status = 'A'
) AND
NOT EXISTS
(
SELECT *
FROM MyTable T3
WHERE T3.code = T1.code
AND T3.status <> 'A'
AND NOT EXISTS
(
SELECT *
FROM MyTable T4
WHERE T4.code = T3.code
AND T4.subcode = T3.subcode
AND T4.status = 'A'
)
)
In your select, add a where clause that reads:
Select [stuff]
From Table T
Where Exists
(Select * From Table
Where Code = T.Code
And Status = 'A')
And Not Exists
(Select * From Table I
Where Code = T.Code
And Not Exists
(Select * From Table
Where Code = I.Code
And SubCode = I.SubCode
And Status = 'A'))
In English,
Show me the rows,
where there is at least one row with status 'A',
and there are NO rows with any specific subcode,
that do not have at least one row with that code/subcode, with status 'A'
INSERT theTempTable (Code)
SELECT t.Code
FROM theTable t
LEFT OUTER JOIN theTable subT ON (t.Code = subT.Code AND subT.status <> 'A')
WHERE subT.Code IS NULL
GROUP BY t.Code
This should do the trick. The logic is a little tricky, but I'll do my best to explain how it is derived.
The outer join combined with the IS NULL check allows you to search for the absence of a criteria. Combine that with the inverse of what you're normally looking for (in this case status = 'A') and the query succeeds when there are no rows that do not match. This is the same as ((there are no rows) OR (all rows match)). Since we know that there are rows due to the other query on the table, all rows must match.