Select an ID where there is only one row and that row is a specific value - sql

I have this query. There's a lot of joins because I am checking if an ID is linked to any of those tables.
Currently, this query shows me any ID's that are not linked to any of those tables. I would like to add to it so that it also shows any IDs that are linked to the d table, but only if there is only 1 row in the D table and the type in the D field is 'member'.
SELECT
c.ID,
c.location,
c.pb,
c.name,
c.surname
FROM c
LEFT JOIN l on c.rowno = l.rowno
LEFT JOIN d on c.rowno = d.rowno
LEFT JOIN t on c.rowno = t.rowno
LEFT JOIN cj ON (c.rowno = cj.rowno OR c.rowno = cj.rowno2)
LEFT JOIN dj ON c.rowno = d.rowno
LEFT JOIN lg ON c.rowno = lg.rowno
LEFT JOIN tj ON c.rowno = tj.rowno
WHERE
c.status != 'closed'
AND l.rowno IS NULL
AND d.rowno IS NULL
AND t.rowno IS NULL
AND cj.rowno IS NULL
AND dj.rowno IS NULL
AND lg.rowno IS NULL
AND tj.rowno IS NULL
My first thought is to just add
WHERE D.type = 'member'
But that gives me all IDs that have a row with D.type = member (they could have 10 rows with all different types, but as long as 1 of those has type = member it shows up). I want to see ID's that ONLY have d.type = member
I'm sorry if I'm wording this badly, I'm having trouble getting this straight in my head. Any help is appreciated!

I would use exists for all conditions except the one on the D table:
SELECT c.*
FROM c JOIN
(SELECT d.rownum, COUNT(*) as cnt,
SUM(CASE WHEN d.type = 'Member' THEN 1 ELSE 0 END) as num_members
FROM t
GROUP BY d.rownum
) d
ON c.rownum = d.rownum
WHERE c.status <> 'closed' AND
NOT EXISTS (SELECT 1 FROM t WHERE c.rowno = t.rowno) AND
NOT EXISTS (SELECT 1 FROM l WHERE c.rowno = l.rowno) AND
. . .
I find NOT EXISTS is easier to follow logically. I don't think there is a big performance difference between the two methods in SQL Server.

Related

oracle outer join with condition in where clause

I have a case table and case_status which is a child table. Earlier case_status was a mandatory field but not anymore.
So i had to change from join to left outer join. After adding this join condition the records are not getting picked up when case_status table doesnt have a record for a case.
case_status has a lookup to lkp_case_status hence having an outer join even there.
My query looks like this
select c.* from cases c
left outer join (SELECT case_id,
case_status_id,
COUNT(DECODE(case_status_id, 16, 1, NULL)) OVER (PARTITION BY case_id) AS IS_CLOSED
FROM case_status) cs ON cs.case_id = c.case_id
left outer join lkp_case_status lkp_cs
on lkp_cs.id = cs.case_status_id
where c.case_type = 'P'
and c.delete_date is null
AND cs.is_closed = 0;
I think its the cs.is_closed = 0 is not letting the record to get pulled up.
So i added AND cs.is_closed = 0; within the join condition as below,
select c.* from cases c
left outer join (SELECT case_id,
case_status_id,
COUNT(DECODE(case_status_id, 16, 1, NULL)) OVER (PARTITION BY case_id) AS IS_CLOSED
FROM case_status) cs ON cs.case_id = c.case_id AND cs.is_closed = 0
left outer join lkp_case_status lkp_cs
on lkp_cs.id = cs.case_status_id
where c.case_type = 'P'
and c.delete_date is null;
But this query is pulling all the records irrespective of the decode condition in the 3rd line.
3rd line - if case_status = 16, which means case is closed and dont pull the record.
Any inputs on how to make it work. Basically it has to pull all the records from cases table , if caseStatus table has a value of case_status = 16 dont pull the case record too.
case
id name
1 AAA
2 BBB
3 CCC
case_status
1 16
2 1
Output should show as follows:
Result:
id name
2 BBB
3 CCC
But what am getting is
id name
2 BBB
My query is not picking case with id = 3.
Any help is highly appreciated. Thank you.
If you want to add a filtering predicate for an outer-joined table or table expression you'll need to account for their columns to show up as nulls. You can do:
select c.* from cases c
left outer join (SELECT case_id,
case_status_id,
COUNT(DECODE(case_status_id, 16, 1, NULL))
OVER (PARTITION BY case_id) AS IS_CLOSED
FROM case_status) cs ON cs.case_id = c.case_id
left outer join lkp_case_status lkp_cs
on lkp_cs.id = cs.case_status_id
where c.case_type = 'P'
and c.delete_date is null
AND (cs.is_closed = 0 or cs.is_closed is null); -- changed here

How can I count the same fields

I'm making a query to get the stages of a case. So Now I have three cases with 3 stages (the last stage inserted in the table user_case_stage).
SELECT DISTINCT ON (c.id)
c.id,
f.name
FROM schema.user a
JOIN schema.intern_user b ON a.id = b."userId"
JOIN schema.user_case c ON b.id = c."internUserId"
JOIN schema.user_case_stage d ON c.id = d."userCaseId"
JOIN schema.stage f ON d."stageId" = f.id
WHERE b.id = 1
ORDER BY c.id,d."createdAt" DESC
Result:
caseId stageName
1 "Pasive"
6 "Closed"
7 "Closed"
But I want something to count by stageName like this:
total stageName
1 "Pasive"
2 "Closed"
assumed your logic is correct , since you didn't provide any information, here is how you can do it:
SELECT
f.name
, count(distinct c.id) total
FROM schema.user a
JOIN schema.intern_user b ON a.id = b."userId"
JOIN schema.user_case c ON b.id = c."internUserId"
JOIN schema.user_case_stage d ON c.id = d."userCaseId"
JOIN schema.stage f ON d."stageId" = f.id
WHERE b.id = 1
group by f.name

Get DISTINCT record using INNER JOIN

I have the follwong Query on multi tables
SELECT DISTINCT b.BoxBarcode as [Box Barcode], (select case when b.ImagesCount IS NULL
then 0
else b.ImagesCount end) as [Total Images], s.StageName as [Current Stage] ,d.DocuementTypeName as [Document Type],
u.UserName as [Start User],uu.UserName as [Finished User]
FROM [dbo].[Operations] o
inner join dbo.LKUP_Stages s on
o.stageid=s.id
inner join dbo.LKUP_Users u on
u.id=o.startuserid
left join dbo.LKUP_Users uu on
uu.id=o.FinishedUserID
inner join boxes b on
b.id=o.boxid
inner join LKUP_DocumentTypes d on
d.ID = b.DocTypeID
where b.IsExportFinished = 0
when i select count from the Boxes table where IsExportFinished = 0
i got the Count 42 records, when i run the above qoury i got 71 records,
i want just the 42 records in Boxes table to retrived.
You are doing a one-to-many join, i.e. at least one of the tables have multiple rows that match the join criteria.
Step one is to find which table(s) that give the "duplicates".
Once you have done that you may be able to fix the problem by adding additional criteria to the join. I'm taking a guess that the same boxid occurs several times in the Operations table. If that is the case you need to decide which Operation row you want to select and then update the SQL accordingly.
Try this one -
SELECT
Box_Barcode = b.BoxBarcode
, Total_Images = ISNULL(b.ImagesCount, 0)
, Current_Stage = s.StageName
, Document_Type = d.DocuementTypeName
, Start_User = u.UserName
, Finished_User = uu.UserName
FROM (
SELECT DISTINCT
o.stageid
, o.boxid
, o.startuserid
, o.FinishedUserID
FROM dbo.[Operations]
) o
JOIN dbo.LKUP_Stages s ON o.stageid = s.id
JOIN dbo.boxes b ON b.id = o.boxid
JOIN dbo.LKUP_DocumentTypes d ON d.id = b.DocTypeID
JOIN dbo.LKUP_Users u ON u.id = o.startuserid
LEFT JOIN dbo.LKUP_Users uu ON uu.id = o.FinishedUserID
WHERE b.IsExportFinished = 0
I guess that if you change your LEFT JOIN into INNER JOIN you will get 42 records as requested.

SQL Server Query Returning Same Row Twice

I seem to be having trouble with the following query. It basically works, but I have a case where it is returning one row from mc_WorkoutDetails twice!
Here's the original query:
ALTER PROCEDURE [dbo].[mc_Workouts_GetActivities]
#WorkoutID bigint
AS
BEGIN
SET NOCOUNT ON
SELECT d.ID, a.Description,
CASE WHEN Reps = 0 THEN NULL ELSE Reps END AS Reps,
CASE WHEN Sets = 0 THEN NULL ELSE Sets END AS Sets,
CASE WHEN Minutes = 0 THEN NULL ELSE Minutes END AS Minutes,
d.Comments, c.Name AS Category, a.CategoryID,
(CASE WHEN v.ActivityID IS NULL THEN 0 ELSE 1 END) AS HasVideo,
a.ID AS ActivityID
FROM mc_WorkoutDetails d
INNER JOIN mc_Activities a ON d.ActivityID = a.ID
INNER JOIN mc_Activities_Categories c ON a.CategoryID = c.ID
LEFT OUTER JOIN mc_TrainerVideos v ON a.ID = v.ActivityID
WHERE (d.WorkoutID = #WorkoutID)
ORDER BY SortOrder, a.Description
RETURN ##ERROR
END
Then I tried changing:
INNER JOIN mc_Activities a ON d.ActivityID = a.ID
INNER JOIN mc_Activities_Categories c ON a.CategoryID = c.ID
To:
LEFT OUTER JOIN mc_Activities a ON d.ActivityID = a.ID
LEFT OUTER JOIN mc_Activities_Categories c ON a.CategoryID = c.ID
But that didn't seem to help. I still get the duplicate row.
Can anyone see what's happening?
What you can do is add a join back to the same table using a group to weed out the duplicate rows.
So add this to your join after FROM mc_WorkoutDetails d:
inner join (select [columns you want to select], max(id) id
from mc_WorkoutDetails
group by [columns you want to select] ) q on q.id = d.id
Let me know if that makes sense. Basically you are doing a distinct and getting the max id so you eliminate one of the rows in the join. You have to remember that even if you want there to be duplicates, they will be eliminated even if they are suppose to be there.
The full alter would be:
ALTER PROCEDURE [dbo].[mc_Workouts_GetActivities]
#WorkoutID bigint
AS
BEGIN
SET NOCOUNT ON
SELECT d.ID, a.Description,
CASE WHEN Reps = 0 THEN NULL ELSE Reps END AS Reps,
CASE WHEN Sets = 0 THEN NULL ELSE Sets END AS Sets,
CASE WHEN Minutes = 0 THEN NULL ELSE Minutes END AS Minutes,
d.Comments, c.Name AS Category, a.CategoryID,
(CASE WHEN v.ActivityID IS NULL THEN 0 ELSE 1 END) AS HasVideo,
a.ID AS ActivityID
FROM mc_WorkoutDetails d
inner join (select Reps, Sets, Comments, Minutes, max(id) id
from mc_WorkoutDetails
group by Reps, Sets, Comments, Minutes ) q on q.id = d.id
INNER JOIN mc_Activities a ON d.ActivityID = a.ID
INNER JOIN mc_Activities_Categories c ON a.CategoryID = c.ID
LEFT OUTER JOIN mc_TrainerVideos v ON a.ID = v.ActivityID
WHERE (d.WorkoutID = #WorkoutID)
ORDER BY SortOrder, a.Description
RETURN ##ERROR
END
Thanks for everyone's input. The general suggestions here were correct: I had two rows in the mc_workoutDetails table that referenced the same row in the mc_Activities table.
While the foreign key was part of a unique primary key, it was a compound key and so this column could contain duplicates as long as the other column in the key were different.

SQL Dynamic join?

Please see http://sqlfiddle.com/#!3/2506f/2/0
I have two tables. One is a general record, and the other is a table containing related documents that link to that record.
In my example I've created a straightforward query which shows all records and their associated documents. This is fine, but I want a more complex situation.
In the 'mainrecord' table there is a 'multiple' field. If this is 0, then I only want the most recent document from the documents table (that is, with the highest ID). If it is 1, I want to join all linked documents.
So, rather than the result of the query being this:-
ID NAME MULTIPLE DOCUMENTNAME IDLINK
1 One 1 first document 1
1 One 1 second document 1
2 Two 0 third document 2
2 Two 0 fourth document 2
3 Three 1 fifth document 3
3 Three 1 sixth document 3
It should look like this:-
ID NAME MULTIPLE DOCUMENTNAME IDLINK
1 One 1 first document 1
1 One 1 second document 1
2 Two 0 fourth document 2
3 Three 1 fifth document 3
3 Three 1 sixth document 3
Is there a way of including this condition into my query to get the results I'm after. I'm happy to explain further if needed.
Thanks in advance.
WITH myData
AS
(SELECT mainrecord.*, documentlinks.documentName, documentlinks.idlink,
Row_number()
OVER (
partition BY mainrecord.ID
ORDER BY mainrecord.ID ASC) AS ROWNUM
FROM mainrecord INNER JOIN documentlinks
ON mainrecord.id = documentlinks.idlink)
SELECT *
FROM mydata o
WHERE multiple = 0 AND rownum =
(SELECT max(rownum) FROM mydata i WHERE i.id = o.id)
UNION
SELECT *
FROM myData
WHERE multiple = 1
http://sqlfiddle.com/#!3/2506f/57
Another solution (tested at SQL-Fiddle):
SELECT m.*,
d.id as did, d.documentName, d.IDLink
FROM mainrecord AS m
JOIN documentlinks AS d
ON d.IDLink = m.id
AND m.multiple = 1
UNION ALL
SELECT m.*,
d.id as did, d.documentName, d.IDLink
FROM mainrecord AS m
JOIN
( SELECT d.IDLink
, MAX(d.id) AS did
FROM mainrecord AS m
JOIN documentlinks AS d
ON d.IDLink = m.id
AND m.multiple = 0
GROUP BY d.IDLink
) AS g
ON g.IDLink = m.id
JOIN documentlinks AS d
ON d.id = g.did
ORDER BY id, did ;
This will probably do:
SELECT mainrecord.name, documentlinks.documentname
FROM documentlinks
INNER JOIN mainrecord ON mainrecord.id = documentlinks.IDLink AND multiple = 1
UNION
SELECT mainrecord.name, documentlinks.documentname
FROM (SELECT max(id) id, IDLink FROM documentlinks group by IDLink) maxdocuments
INNER JOIN documentlinks ON documentlinks.id = maxdocuments.id
INNER JOIN mainrecord ON mainrecord.id = documentlinks.IDLink AND multiple = 0
How about this:
select * from mainrecord a inner join documentlinks b on a.Id=b.IDLink
where b.id=(case
when a.multiple=1 then b.id
else (select max(id) from documentlinks c where c.IDLink=b.IDLink) end)
SQL FIDDLE
select
m.ID, m.name, m.multiple, dl.idlink,
dl.documentName
from mainrecord as m
left outer join documentlinks as dl on dl.IDlink = m.id
where
m.multiple = 1 or
not exists (select * from documentlinks as t where t.idlink = m.id and t.id < dl.id)