Transact-SQL Select Query Giving duplicate values - sql

first off, thank you for taking the time to look at this.
I am trying to collect data from 3 tables and make a reference chart that allows the end user to see the stored data.
Basically I have 3 tables for this example:
USERS:
USER_PK USER_ID USER_NAME
1 10000 Bob
2 10001 Sally
3 10003 Joe
4 10004 Susan
SKILL_TYPE:
SKILL_PK SKILL_NAME
11 Point of Sale
22 Digital Sales
33 Customer Service
44 Specialist Support
SKILL_ASSOCIATION:
SKILL_ASSOC_PK SKILL_PK USER_PK START_DATE STOP_DATE Priority
99 11 1 36526 500000 2
88 11 2 36527 500000 3
77 22 1 36526 500000 3
66 33 3 36528 500000 1
55 44 4 36525 500000 1
444 33 4 36525 500000 4
(I know I've probably broken some rules with cataloging this data I did it in SQL Express, however it is only an example and not representative of the real data I am using)
My Select Query Returns an unwanted result with multiple lines for each USER:
Statement:
SELECT USERS.[USER_NAME], USERS.[USER_ID],
(CASE WHEN ST.SKILL_NAME ='Point of Sale' Then SA.[PRIORITY] END) AS 'POS',
(CASE WHEN ST.SKILL_NAME ='Digital Sales' Then SA.[PRIORITY] END) AS 'DS',
(CASE WHEN ST.SKILL_NAME ='Customer Service' Then SA.[PRIORITY] END) AS 'CS',
(CASE WHEN ST.SKILL_NAME ='Specialist Support' Then SA.[PRIORITY] END) AS 'Spec'
FROM USERS
INNER JOIN [dbo].[SKILL_ASSOCIATION] AS SA ON SA.USER_PK = USERS.USER_PK
INNER JOIN SKILL_TYPE AS ST ON ST.SKILL_PK = SA.SKILL_PK
Result:
USER_NAME USER_ID POS DS CS Spec
Bob 10000 2 NULL NULL NULL
Sally 10001 3 NULL NULL NULL
Bob 10000 NULL 3 NULL NULL
Joe 10003 NULL NULL 1 NULL
Susan 10004 NULL NULL NULL 1
Susan 10004 NULL NULL 4 NULL
I've tried using distinct as well with similar results.
Desired Results:
NAME ID POS DS CS Spec
Bob 1 2 3
Sally 2 3
Joe 1
Susan 4 1
I have very limited Query access with this SQL Server and cannot create/modify or delete from it to accomplish my objective.
Any guidance would be much appreciated!
Thanks,
Steven

Your expected output implies that an aggregation by user along with taking the MAX of each of the CASE expressions should work:
SELECT
u.[USER_NAME],
u.[USER_ID],
MAX(CASE WHEN ST.SKILL_NAME = 'Point of Sale' THEN SA.[PRIORITY] END) AS POS,
MAX(CASE WHEN ST.SKILL_NAME = 'Digital Sales' THEN SA.[PRIORITY] END) AS DS,
MAX(CASE WHEN ST.SKILL_NAME = 'Customer Service' THEN SA.[PRIORITY] END) AS CS,
MAX(CASE WHEN ST.SKILL_NAME = 'Specialist Support' THEN SA.[PRIORITY] END) AS Spec
FROM USERS u
INNER JOIN [dbo].[SKILL_ASSOCIATION] AS SA
ON SA.USER_PK = u.USER_PK
INNER JOIN SKILL_TYPE AS ST
ON ST.SKILL_PK = SA.SKILL_PK
GROUP BY
u.[USER_NAME],
u.[USER_ID];

Related

Is it possible to pivot on two columns? (if that's even the correct way to ask this?)

I am trying to create a report that prints our home room counts in a readable format. We currently have an Excel Template that is manually filled out but I would like to automate this process within SQL so we can just pull the report from the database. Since this is public school data I won't post my sub-query or "real" data but I'll try to be as specific as possible.
I have a subquery that pulls student_ID, School_Title, Grade_Level, and HomeRoom that I named Data. For the purposes of this dicussion, let's assume Data is actually a table in my database. I have been working on using a pivot, but it doesn't seem to do what I need. We have multiple schools, each with multiple homerooms per grade level. There are different numbers of homerooms per grade level per school depending on the size of the school. (So School 1 might have only 2 Kindergarten homerooms, but School4 might have 4 homerooms for Kindergarten).
Data looks like this:
Student_ID School_Title Grade_Level HomeRoom
12345 School1 KA HR1
23456 School1 KP HR2
34567 School1 01 HR3
45678 School1 01 HR4
......
56789 School7 06 HR100
The query I am using right now is (in SQL Server 2012):
SELECT *
FROM Data
PIVOT (Count(student_ID)
FOR GRADE_LEVEL IN ([KA],[KP],[01],[02],[03],[04],[05],[06])
) as PivotStudents
ORDER BY School_Title
But what I get out is:
School_Title HomeRoom KA KP 01 02 03 04 05 06
School 1 HR1 25 0 0 0 0 0 0 0
School 1 HR2 0 26 0 0 0 0 0 0
School 1 HR3 0 0 19 0 0 0 0 0
School 1 HR4 0 0 21 0 0 0 0 0
....
School 7 HR100 0 0 0 0 0 0 0 27
What I want to get out is:
School_Title HR KA HR KP HR 01 HR 02...
School 1 HR1 25 HR2 26 HR3 19 HR5 23
School 1 HR4 21
...
School 7 HR91 19 HR92 19 HR93 20 HR98 21
School 7 HR94 17 HR95 23 HR96 18 HR99 24
School 7 HR97 22
I don't care which are grouped together "in a row". So, in my head, HR3 happened to be the first grade 01 homeroom found so it's in row 1. But HR4 is also a grade 01 homeroom at School 1 and is the next one found so it goes into row 2.
It is possible for a homeroom to have multiple grade levels too (though only in 2 cases but I need to account for it being possible).
So basically, is the output I'm going for even possible within SQL? Do I need to get out of the database into Crystal or something to be able to "place" the data where I want it to go or can I give SQL enough information to format it how I want.
Thanks!
DBs
You can do this using aggregates with case statements.. the key will be to add a DENSE_RANK column to your data to separate the aggregates into rows.
SELECT
[School_Title],
[HR] = MAX(CASE WHEN [Grade_Level] = 'KA' THEN [HomeRoom] END),
[KA] = COUNT(CASE WHEN [Grade_Level] = 'KA' THEN [Student_ID] END),
[HR] = MAX(CASE WHEN [Grade_Level] = 'KP' THEN [HomeRoom] END),
[KP] = COUNT(CASE WHEN [Grade_Level] = 'KP' THEN [Student_ID] END),
[HR] = MAX(CASE WHEN [Grade_Level] = '01' THEN [HomeRoom] END),
[01] = COUNT(CASE WHEN [Grade_Level] = '01' THEN [Student_ID] END)
-- etc
FROM
(
SELECT *,
DENSE_RANK() OVER (PARTITION BY [School_Title], [Grade_Level] ORDER BY [HomeRoom]) Rn
FROM [Data]
) d
GROUP BY [School_Title], [RN]
SQL FIDDLE
Similar to above by Jamie, but changed the Count to happen with the Data Subquery and used Max for all the case statements so...
Select
School_Title,
[HR1]=MAX(CASE WHEN [grade_level]='KA' THEN [HomeRoom] END),
[KA]=MAX(CASE WHEN [grade_level]='KA' THEN [Number] END),
[HR2]=MAX(CASE WHEN [grade_level]='KP' THEN [HomeRoom] END),
[KP]=MAX(CASE WHEN [grade_level]='KP' THEN [Number] END),
..... etc.
From (
select *, ROW_NUMBER() OVER (PARTITION BY School_Title, Grade_LEvel ORDER by HomeRoom) Rn
from (
select count(student_id) as Number, School_Title, Grade_Level, HomeRoom
from Data
group by School_Title, Grade_Level, HomeRoom) data2
GROUP BY School_Title, Rn
ORDER BY SCHOOL_Title
I need to add some IsNull somewhere along the line so that a school that has 4 homerooms of grade 1 but only 3 homerooms of grade 2 doesn't have NULL/NULL chilling in the last row for that school, but all in all, I can't believe this can actually be done in SQL!!!

Oracle query stumped - derived table

It's been a long time since I've done more than the most basic sql queries. But I ran into this one today and have spent a few hours on it and am stuck with my derived table attempt (this is for an Oracle db). Looking for a few tips. Thx.
TABLE: dtree
DataID Name
-------------
10001 A.doc
10002 B.doc
10003 C.doc
10004 D.doc
TABLE: collections
CollectionID DataID
---------------------
201 10001
201 10002
202 10003
203 10004
TABLE: rimsNodeClassification
DataID RimsSubject RimsRSI Status
---------------------------------------
10001 blah IS-03 Active
10002 blah LE-01 Active
10003 blah AD-02 Active
10004 blah AD-03 Active
TABLE: rsiEventSched
RimsRSI RetStage DateToUse RetYears
--------------------------------------
IS-03 SEM-PHYS 95 1
IS-03 ACT NULL 2
LE-01 SEM-PHYS 94 1
LE-01 INA-PHYS 95 2
LE-01 ACT NULL NULL
LE-01 OFC NULL NULL
LE-02 SEM-PHYS 94 2
Trying to query on CollectionID=201
INTENDED RESULT:
DataID Name RimsRSI Status SEMPHYS_DateToUse INAPHYS_DateToUse SEMPHYS_RetYears INAPHYS_RetYears
-------------------------------------------------------------------------------------------------------
10001 A.doc IS-03 Active 95 null 1 null
10002 B.doc Le-01 Active 94 95 1 2
You don't need a Derived Table, just join the tables (the last using a Left join) and then apply a MAX(CASE) aggregation:
select c.DataID, t.Name, rnc.RimsRSI, rnc.Status,
max(case when res.RetStage = 'SEM-PHYS' then res.DateToUse end) SEMPHYS_DateToUse,
max(case when res.RetStage = 'INA-PHYS' then res.DateToUse end) INAPHYS_DateToUse,
max(case when res.RetStage = 'SEM-PHYS' then res.RetYears end) SEMPHYS_RetYears,
max(case when res.RetStage = 'INA-PHYS' then res.RetYears end) INAPHYS_RetYears
from collections c
join dtree t
on c.DataID = t.DataID
join rimsNodeClassification rnc
on c.DataID = rnc.DataID
left join rsiEventSched res
on rnc.RimsRSI = res.RimsRSI
where c.CollectionID= 201
group by c.DataID, t.Name, rnc.RimsRSI, rnc.Status

transpose rows to columns in db2

I have a query output as below
Customer policytype plan amount
Sam ulip P1 250
Sam ulife u1 435
Sam Ulip P2 370
Hazar Ulip P1 679
Hazar Ulife u1 567
And so on ....
I need to transpose above output as follows
Customer ulip ulife
Sam 250 435
Sam 370 Null
Hazar 679 567
Can someone help me to achieve above result in db2
Use conditional Aggregate
SELECT customer,
Max(CASE WHEN policytype = 'ulip' THEN amount END) AS ulip,
Max(CASE WHEN policytype = 'ulife' THEN amount END) AS ulife
FROM Youratable
GROUP BY customer,
CASE WHEN plan IN ( 'p1', 'u1' ) THEN 1 ELSE 0 END

Find count from specific table by specific filter sql server

I am Having table like this:
id candid candname status date time location jobcode
1 12 hhhhhhhhhh Introduce 2014-05-21 14:0 NewYork 10JN
3 12 hhhhhhhhhh Reject 2014-05-21 15:0 AM London 10JN
4 12 hhhhhhhhhh Interview 2014-05-21 15:0 PM Chicago 10JN
5 11 Pinky Bare Introduce 2014-05-21 65:6 India 10JN
6 11 Pinky Bare Interview 2014-05-21 4:56 AM 10JN
7 13 chetan Tae Introduce 2014-05-21 4:54 AM Nagpur faOl
8 13 chetan Tae Interview 2014-05-21 3:45 Pune faOl
9 14 manisha mane Introduce 2014-05-21 3:33 PM Pune faOl
10 18 ranju gondane Introduce 2014-05-28 3:44 Nagpur AQW-06
12 18 ranju gondane Interview 2014-05-28 5:45 45454 AQW-06
13 18 ranju gondane Reject 2014-05-28 43:43 rsds AQW-06
14 19 vandanna rai Introduce 2014-05-28 7:7 yyyr AQW-06
if i use query
SELECT COUNT(*) FROM [tablename]
WHERE
(jobcode='AQW-06')
AND
([status] <> 'Interview' AND [status] <> 'Reject'
AND
[status] <> 'ON-Hold' AND [status] <> 'Hire')
I get count 2 for introduce candidates..
if the candidate is interviewd after introduce, it will not counted as Introduce
I want the count of Introduce, interviewd, rejected candidates of specofic jobcode
Please help me for this.
You can try
select status, count(*)
from [tablename]
where jobcode = 'AQW-06'
group by status
Edit: You can try use something like this
select count(x.candid) numofcandidates, x.statusnum
from
(select candid, max(case when status = 'Reject' then 3
when status = 'Interview' then 2
when status = 'Introduce' then 1 end) statusnum
from [tablename] t
where jobcode = 'AQW-06'
group by candid) x
group by x.statusnum;
What I actually did is to "translate" the status to a number, so I can use the highest status first. All you need to do then it to "translate" back the statusnum to the values of your table. In my opinion I would use a statusnum in my table directly
Try this:
;with reftable as
(select 1 'key', 'Introduce' 'val'
union
select 2 'key', 'Interview' 'val'
union
select 3 'key', 'Rejected' 'val'
),
cte as
(select e.candid, e.[status], row_number() over (partition by e.candid order by r.[key] desc) rn
from yourtable e
inner join reftable r on e.[status] = r.val
where e.[status] in ('Introduce','Interview','Rejected')
and e,jobcode = 'AQW-06')
select [status], count([status])
from cte
where rn = 1
group by [status]
Basically, we assign a numeric value to your text status to allow sorting. In the over clause, we sort by this numeric value in descending order to get the highest status of a candidate as you describe. Then, we just count the number of occurrences of each status.
Note that you can extend this to include values for status like 'Hire'. To do this, you will need to add it to the list in reftable with appropriate numeric value, and also add it to the filter in cte.
I want the count of Introduce, interviewed, rejected candidates of specific jobcode
The query below will return the results you need:
SELECT SUM(t.IsIntroduction) AS CountOfIntroductions,
SUM(t.IsInterview) AS CountOfInterviews,
SUM(t.IsRejected) AS CountOfRejections
FROM (
SELECT id,
CASE WHEN Status = 'Introduce' THEN 1 ELSE 0 END AS IsIntroduction,
CASE WHEN Status = 'Interview' THEN 1 ELSE 0 END AS IsInterview,
CASE WHEN Status = 'Reject' THEN 1 ELSE 0 END AS IsRejected
FROM [Tablename]
WHERE JobCode = 'AQW-06'
) AS t
Sample at this SQL Fiddle.

SQL query to pivot a column using CASE WHEN

I have the following table:
Bank:
name val amount
John 1 2000
Peter 1 1999
Peter 2 1854
John 2 1888
I am trying to write an SQL query to give the following result:
name amountVal1 amountVal2
John 2000 1888
Peter 1999 1854
So far I have this:
SELECT name,
CASE WHEN val = 1 THEN amount ELSE 0 END AS amountVal1,
CASE WHEN val = 2 THEN amount ELSE 0 END AS amountVal2
FROM bank
However, it gives the slightly wrong result:
name amountVal1 amountVal2
John 2000 0
Peter 1999 0
John 0 1888
Peter 0 1854
How can I modify my query to give the correct presentation?
Thanks
SELECT
name,
SUM(CASE WHEN val = 1 THEN amount ELSE 0 END) AS amountVal1,
SUM(CASE WHEN val = 2 THEN amount ELSE 0 END) AS amountVal2
FROM bank GROUP BY name
Looks like you need to join the table on itself. Try this:
select bank1.name, bank1.amount, bank2.amount
from bank bank1
inner join bank bank2 on
bank1.name = bank2.name
and bank1.val = 1
and bank2.val = 2