Including rows with no values in SQL query output - sql

Running the following query in my SQL SERVER 2016 database:
SELECT
u.idnumber,
gi.idnumber AS code,
gg.finalgrade AS grade
FROM
grades AS gg
INNER JOIN grade_items AS gi ON gg.itemid = gi.id
INNER JOIN users AS u ON gg.userid = u.id
WHERE gi.idnumber IN ('436','434','313','002','135')
AND (u.idnumber = 'JohnBrown-xyz123);
gives me this result:
-------------------------
idnumber code grade
-------------------------
John12558 313 96
John12558 135 83
How can I include a row for ALL the 5 gi.idnumber's, including the rows with no grade?
-------------------------
idnumber code grade
-------------------------
John12558 436
John12558 434
John12558 313 96
John12558 002
John12558 135 83
Database tables:
user
id PK
grade_items
id PK
grade_grades
grade_grades.itemid FK (grade_items)
grade_grades.userid FK (user)

You can use value construct like that :
select tt.idnumber,
t.idnumber AS code,
tt.grade
from (values ('436'), ('434'), ('313'), ('002'), ('135')) t (idnumber)
left join (select
u.idnumber,
gi.idnumber AS code,
gg.finalgrade AS grade
from grades AS gg
inner join grade_items AS gi ON gg.itemid = gi.id
inner join users AS u ON gg.userid = u.id
where u.idnumber = 'JohnBrown-xyz123') tt on left(tt.code, 3) = t.idnumber
If, idnumber has numeric type, then you don't need to use ' '.

You need cross join to see all you want:
select
u.idnumber,
gi.idnumber code,
ISNULL(gg.finalgrade, 0) grade
from users u
cross join grade_items gi
left outer join grades gg on gg.itemid = gi.id and gg.userid = u.id
where gi.idnumber in ('436','434','313','002','135')
and u.idnumber = 'JohnBrown-xyz123'
nulls in finalgrade cannot be replaced with 'N/A' because they are numbers, not strings, I replaced them with zero.

Assuming "no value" is NULL then just add an extra clause to your WHERE:
WHERE (LEFT(gi.idnumber, 3) IN ('436','434','313','002','135')
OR gi.idnumber IS NULL)
Edit: Apaprently, the above does not work, which implies that "no value" does not mean NULL. you could, instead, therefore try:
WHERE (LEFT(gi.idnumber, 3) IN ('436','434','313','002','135','')
If this doesn't work, please provide consumable sample data, which we can test against: Forum Etiquette: How to post data for a T-SQL Question

Related

Selecting Rows That Have One Value but Not Another

I need a get some rows of two tables with join that shoud have one value in a column (1407) but shouldn't have other value (1403)
These is the tables and the query:
select a.job, a.date, b.group from log a inner join active_tmp b
on a.jobno=b.jobno and a.no=b.no where b.list = 'N'
AND LOGDATE = TO_CHAR(TRUNC(SYSDATE),'YYYYMMDD')
and a.job not like 'HOUSE%'
and a.job not like 'CAR%' and (errorCode=1047 and errorCode<>1403);
LOG
JOB DATE LOGDATE JOBNO NO errorCode
MAM 20220123 20220125 33 22 1047
MAM 20220123 20220125 33 22 1403
DAD 20220122 20220125 11 99 1047
MAM 20220122 20220125 33 22 0323
DAD 20220122 20220125 11 99 0444
ACTIVE_TMP
JOB JOBNO NO GROUP LIST
MAM 33 22 LAPTOP N
MAM 33 22 LAPTOP N
DAD 11 99 KEY N
But I get:
MAM,20220123,LAPTOP
DAD,20220122,KEY
I need:
DAD,20220122,KEY
Because MAM have both codes (1047 and 1043).
To rephrase, I think you mean "I want to return matching rows that have error code 1047 but for which the same values of jobno, no, list do not have a corresponding row with error code 1403"
This part is redundant:
AND (errorCode = 1047 AND errorCode <> 1403);
If you are saying errorCode must be 1047, you are also saying it is not equal to 1403.
I think you want to select some rows into some result set, then check that there's not another row that disqualifies one of the selected rows from the final result.
So,
SELECT a.job,
a.date,
b.group
FROM _log a
INNER JOIN _active_tmp b
ON a.jobno = b.jobno
AND a.no = b.no
WHERE b.list = 'N'
AND LOGDATE = TO_CHAR(CURRENT_TIMESTAMP,'YYYYMMDD')
AND a.job NOT LIKE 'HOUSE%'
AND a.job NOT LIKE 'CAR%'
AND a.errorCode = 1047
AND NOT EXISTS (SELECT 1
FROM _log c
INNER JOIN _active_tmp d
ON c.jobno = d.jobno
AND c.no = d.no
WHERE a.job = c.job
AND a.date = c.date
AND b.group = d.group
AND c.errorCode = 1403)
We select the rows that satisfy the join and have error code 1047 then subtract from that set those rows that also satisfy the join but have error code 1403. You could possibly make this more terse using CTE or a temp table, but this works too.
Note I had to change a few things to make it work in my engine (Postgres), so you may have to change a few things back to Oracle.
You need to change the error code logic. Identify what JOB values has 1403 and then exclude those values
select distinct a.job, a.date, b.[group] from LOG a inner join active_tmp b
on a.jobno=b.jobno and a.no=b.no where b.list = 'N'
AND LOGDATE = TO_CHAR(TRUNC(SYSDATE),'YYYYMMDD')
and a.job not like 'HOUSE%'
and a.job not like 'CAR%' and a.job not in (select JOB from log where errorCode in(1403));

To join four table in mssql

MaingroupTable
MubGroupCodeid MainName maincode
1 Health 098
2 Social 078
SubGroup Table
SubGroupCodeid SubName subcode
1 Nursing 211
2 Civics 224
SubandMainGroup table
subandmainid **MubGroupCodeid** **subgroupcodeid**
1 1 1
2 2 2
Student Table
studid studname **subandmainid** (foriegn key of **subandmain group** table)
1 Alex 1
2 siraj 2
then I want to join and concatinate studname-maingroupcode-subgroupcode to get output like below
Alex-098-211
siraj-078-224
This will get you started and explain the joins. You'll probably also want to do some casting for the maincode and subcode, but since it's not 100% clear they aren't already varchar values I left that out.
SELECT s.studname + '-' + m.maincode + '-' + s.subcode
FROM Student s
INNER JOIN SubandMainGroup smg on smg.subandmainid = s.subandmainid
INNER JOIN MainGroup m on m.mubgroupcodeid = smg.mubgroupcodeid
INNER JOIN SubGroup s on s.subgroupcodeid = smg.subgroupcodeid
use join and concat all the required column by using ||
select s.studname ||'-'||subG.subcode ||'-' M.maincode
from
Student s join SubandMainGroup subM on s.subandmainid=subM.subandmainid
join SubGroup subG on subG.SubGroupCodeid=subM.subgroupcodeid
join MaingroupTable M on M.MubGroupCodeid=subM.MubGroupCodeid
Use the below query to solve the problem.
select stu.studname + '-'+mgrp.maincode +'-'+sgrp.subcode from Student_ stu
join Maingroup mgrp on stu.studid=mgrp.MubGroupCodeid
join SubGroup sgrp on sgrp.SubGroupCodeid=stu.studid

how to show zero when IN does not return any value sql

I want to return 0 when no rows found for this following condition.
SELECT P.externalid,
Count(DISTINCT Pp.patientuid) patcount
FROM PatientProcedure Pp (nolock )
INNER JOIN visit Temp (nolock )
ON Temp.patientuid = Pp.patientuid
AND (Pp.effectivedate = Temp.VisitDate)
AND Temp.RenderringProviderUid = Pp.serviceprovideruid
AND Temp.VisitDate >= '07-01-2013'
AND Temp.VisitDate <= '06-30-2014'
INNER JOIN serviceprovider Sp (nolock )
ON Pp.serviceprovideruid = Sp.serviceprovideruid
AND Sp.inactive = 0
INNER JOIN MasterCode Mc (nolock )
ON Mc.codeuid = Pp.procedurecodeuid
INNER JOIN MasterCodeSet Mcs (nolock )
ON Mcs.Value = Mc.code
INNER JOIN practice P
ON P.PracticeUid = Temp.practiceuid
WHERE NAME = 'Visual_Field_Exam'
AND Temp.mastervisittypeuid IS NOT NULL
AND P.ExternalID IN ('26900', '26902', '26903', '26906',
'26907', '26908', '26946', '26963',
'27128', '27131', '27133', '27134',
'27135', '27137', '27166', '27167',
'27497', '27498', '27499', '27501',
'27502', '27504', '27505', '27509',
'27510', '27511', '27518')
GROUP BY P.ExternalID
I have found patient count for many practices but no patient found for one practice. So, I want to return count(patientuid) = 0 for that practice.
Here is the sample data.
PracticeId Patcount
26900 2583
26902 826
26903 4085
26906 241
26907 3205
26908 4592
26946 344
26963 398
27128 238
27131 2467
27133 975
27135 815
27137 1252
27166 1038
27167 211
27497 1053
27498 934
27499 3467
27501 617
27502 3511
27504 7222
27505 683
27509 210
27510 1145
27511 181
27518 500
In above output I got data for 26 practices, but "27134" practice does not having patient count, so i want it show 0.
I want above output. How can I achieve it?
Thanks in advance..!
Suppose you have a table Practicer which holds the practicers (i do not know if that is the correct word, but doesn't matter for SQL). Then you need to left join that table with Patient in order to get a list of all Practicers filter by you where clause. So this will get the ones you want.
Select PR.PracticeName,
count(distinct patientid)
from Practicer PR
LEFT JOIN Patient P
ON PR.Practiceid = P.Practiceid
where PR.Practiceid in
('12345','65478','78541')
GROUP BY PR.PracticeName
In general, you want to return 2 fields. The first is the list of Hospitals, Practiotioners or whatever else you may like. In order to get the full list (even if it does not have a count) you need to start with that table.
Lets say we have a table Hospitals that we want to filter on specific ids. The we would have the following query:
SELECT HospitalId,
HospitalName
FROM Hospitals
WHERE HospitalId IN ('26900', '26902', '26903')
Now we would like to know the no of patients in each hospital. We know that hospital with id '26902' has no patients (WOW). If we would go to the Patients table and tried the following:
SELECT HospitalId,
COUNT(*) AS NoOfPatients
FROM Patients
WHERE HospitalId IN ('26900', '26902', '26903')
GROUP BY HospitalId
It would return only ids '26900' and '26903' as the Hospital with id '26902' does not have any patient.
So, how do we figure out the third Hospital?
We join the two tables:
SELECT H.HospitalId,
COUNT(PatienId) AS NoOfPatients
FROM Hospitals H
LEFT JOIN Patients P
WHERE H.HospitalId IN ('26900', '26902', '26903')
GROUP BY H.HospitalId
Now this would return all the requested hospitals with the according number of patients.
Your case is more complex, as we need more joins from the Hospitals to the Patients tables. But i hope my explanation will get you on the right track.
The essence of it is to start from your List Table to your Count table.

Merge results to one column

I have the following query:
SELECT a.User1 as Employee
, isnull(sum(distinct b.Page_Count),0) AS Yesterday
, isnull(sum(distinct c.Page_Count),0) AS Today
, isnull(sum(distinct d.Page_Count),0) AS Week
, e.Material_Location as '(Yesterday)'
, f.Material_Location as '(Today)'
From TaskUser AS a
LEFT JOIN PaperMaterial AS b
ON b.Assigned_To = a.User1
AND b.Date_Assigned between ('06/09/2014') AND ('06/13/2014')
LEFT JOIN PaperMaterial AS c
ON c.Assigned_To = a.User1
AND c.Date_Assigned between ('06/13/2014') AND ('06/14/2014')
LEFT JOIN PaperMaterial AS d
ON d.Assigned_To = a.User1
AND d.Date_Assigned between ('06/09/2014') AND ('06/14/2014')
LEFT JOIN PaperMaterial AS e
ON e.Assigned_To = a.User1
AND e.Date_Assigned between ('06/12/2014') AND ('06/13/2014')
LEFT JOIN PaperMaterial AS f
ON f.Assigned_To = a.User1
AND f.Date_Assigned between ('06/13/2014') AND ('06/14/2014')
GROUP BY a.User1, e.Material_Location, f.Material_Location
Order By a.User1, e.Material_Location, f.Material_Location
If multiple records were input for the same user on the same day, I am getting unique rows for the same person. I only want one row per user with the e and f results merged to the same column.
Ie: Current Output =
Amy 0 640 640 NoTask Task
Amy 0 640 640 Task2 Task
Amy 0 640 640 Task3 Task4
Amy 0 640 640 Task1 NoTask
Requested output:
Amy 0 640 640 (NoTask, Task1, Task2, Task3) (NoTask, Task, Task4)
Here's a greatly over-simplified example of using stuff combined with a correlated subquery:
SQL Fiddle
I used your output as a table, more or less:
select
name,
stuff(
(
select cast(',' as varchar(max)) + mt.one
from MyTable mt
WHERE mt.name = t1.name
order by mt.name
for xml path('')
), 1, 1, '')
from mytable t1
group by name
We're using stuff to concatenate each value for the column I creatively named ONE for each NAME. The correlated subquery allows us to relate each row coming out of that to the corresponding row coming out of the main query.

Get percentages of larger group

The query below is kind of an ugly one so I hope I've got it spaced well enough to make it readable. The query finds the percentage of people that visit a given hospital if they are from a certain area. For instance, if 100 people live in county X and 20 go to hospital A and 80 go to hospital B the query outputs. How the heck is this sort of thing done? Let me know if I need to document the query or whatever I can do to make it clearer.
hospital A 20
hospital B 80
The query below works exactly like I want it to, but it give me thinking: how could this be done for every county in my table?
select hospitalname, round(cast(counts as float)/cast(fayettestrokepop as float)*100,2)as percentSeen
from
(
SELECT tblHospitals.hospitalname, COUNT(tblHospitals.hospitalname) AS counts, tblStateCounties_1.countyName,
(SELECT COUNT(*) AS Expr1
FROM Patient INNER JOIN
tblStateCounties ON Patient.stateCode = tblStateCounties.stateCode AND Patient.countyCode = tblStateCounties.countyCode
WHERE (tblStateCounties.stateCode = '21') AND (tblStateCounties.countyName = 'fayette')) AS fayetteStrokePop
FROM Patient AS Patient_1 INNER JOIN
tblHospitals ON Patient_1.hospitalnpi = tblHospitals.hospitalnpi INNER JOIN
tblStateCounties AS tblStateCounties_1 ON Patient_1.stateCode = tblStateCounties_1.stateCode AND Patient_1.countyCode = tblStateCounties_1.countyCode
WHERE (tblStateCounties_1.stateCode = '21') AND (tblStateCounties_1.countyName = 'fayette')
GROUP BY tblHospitals.hospitalname, tblStateCounties_1.countyName
) as t
order by percentSeen desc
EDIT: sample data
The sample data below is without the outermost query (the as t order by part).
The countsInTheCounty column is the (select count(*)..) part after 'tblStateCounties_1.countyName'
hospitalName hospitalCounts countyName countsInTheCounty
st. james 23 X 300
st. jude 40 X 300
Now with the outer query we would get
st james 0.076 (23/300)
st. jude 0.1333 (40/300)
Here is my guess. You'll have to test against your data or provide proper DDL + sample data.
;WITH totalCounts AS
(
SELECT StateCode, countyCode, COUNT(*) AS totalcount
FROM dbo.Patient GROUP BY StateCode, countyCode
)
SELECT
h.hospitalName,
hospitalCounts = COUNT(p.hospitalnpi),
c.countyName,
countsInTheCounty = tc.totalCount,
percentseen = CONVERT(DECIMAL(5,2), COUNT(p.hospitalnpi)*100.0/tc.totalCount)
FROM
dbo.Patient AS p
INNER JOIN
dbo.tblHospitals AS h
ON p.hospitalnpi = h.hospitalnpi
INNER JOIN
totalCounts AS tc
ON p.StateCode = tc.StateCode
AND p.countyCode = tc.countyCode
INNER JOIN
dbo.tblStateCounties AS c
ON tc.StateCode = c.stateCode
AND tc.countyCode = c.countyCode
GROUP BY
h.hospitalname,
c.countyName,
tc.totalcount
ORDER BY
c.countyName,
percentseen DESC;