PIVOT combined tables with criteria in sql - 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.

Related

SQL Server - Join tables so multiple rows become one row

I'm trying to make a Join statement that will combine two tables, one being for employee information and the other for job role info. The structure of the tables is as follows:
Table 1
Table 2
I would like to join these two tables in such a way that JobKey and JobValue would be the same row as the associated employee, and not create duplicate rows. Normally, a join statement would create this:
Instead, what i would like is something like this:
Is there an effective way to do this?
Edit:
Here is the query I'm currently using to join them:
select * from testTable1 as a left join testTable2 as b on a.EmployeeName = b.EmployeeName
You can use conditional aggregation:
select t1.*, t2.jobkey_1, t2.jobvalue_1, t2.jobkey_2, t2.jobkey_2
from table1 t1 left join
(select t2.employeename,
max(case when seqnum = 1 then jobkey end) as jobkey_1,
max(case when seqnum = 1 then jobvalue end) as jobvalue_1,
max(case when seqnum = 2 then jobkey end) as jobkey_2,
max(case when seqnum = 2 then jobvalue end) as jobvalue_2,
from (select t2.*, row_number() over (partition by employeename order by rowid) as seqnum
from table2 t2
) t2
group by employeename
) t2;
Note: You appear to be using the employee name as the join key between the tables. You should really be using the employee id.

Empty group by with count returns null

I have a query with a count/group by - If no person with the name 'Bob' is found then it returns no rows at all because the GROUP BY is on an empty set - null is returned for the count - I'd like to change the behaviour so that count returns 0 and not null.
select p.Id as personId, count(*) as alias1 from
Table1 as alias2
join Table2 as alias3 on alias3.personId = alias1.Id
where Name = 'Bob'
group by p.Id
Your example was confusing because you're using some alias that don't exist.
Try to use LEFT JOIN.
with
Table1 as
(select 1 as Id, 'Bob' as Name),
Table2 as
(select 2 as personId)
select alias1.Id as personId, count(alias2.personId)
from Table1 as alias1
left join Table2 as alias2 on alias1.Id = alias2.personId
where Name = 'Bob'
group by alias1.Id
Please see:
Count Returning blank instead of 0
Essentially, you can't use GROUP BY and expect no results to return a row.

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

GROUP BY CLAUSE USE

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.

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.