简体   繁体   中英

SQL Server: How to determine if a value exists for a row

I have a data set where 1 column may have 2 different values for each ID. I want to know if there is a way to find out which IDs don't have one of the values.

Here's what a sample of my data set looks like.

Object ID | Relate Type
------------------------
     1    |     P
     1    |     S
     2    |     P
     3    |     S
     4    |     P
     4    |     S

And I want to write a query that will tell me which Objet ID does not have a Relate Type of S.

This was my first attempt:

SELECT [obj_id], COUNT([obj_id]) AS [Successor Count]
 FROM [Prim].[dbo].[relations]
 WHERE [relate_type] = 'S'
 GROUP BY [obj_id]

After thinking about it for a little bit, I realized that this will never give me a Successor Count of 0 because I am specifically querying the Object IDs that have a Relate Type of S. Knowing this, I decided I would probably need some kind of sub query and then I came up with these 2 solutions:

SELECT [obj_id]
FROM [Prim].[dbo].[relations]
WHERE NOT EXISTS
(SELECT DISTINCT [obj_id], [relate_type]
 FROM [Prim].[dbo].[relations]
 WHERE relate_type = 'S')

The above solution doesn't give me the right answer. At least I'm pretty sure it doesn't. Either way, it takes 2.5 minutes to run on a relatively small dataset of 700,000 entries.

The below query I'm pretty sure works and it runs quickly. But I was wondering if there was a different way to do this.

SELECT A.[obj_id]
FROM [Prim].[dbo].[relations] A
LEFT JOIN
    (SELECT DISTINCT [obj_id], [relate_type]
     FROM [Prim].[dbo].[relations]
     WHERE [relate_type] = 'S') B ON A.[obj_id] = B.[obj_id]
WHERE A.[relate_type] != 'S' AND B.[obj_id] IS NULL

This should work:

SELECT *
FROM [Prim].[dbo].[relations] r
WHERE NOT EXISTS(SELECT 1 FROM [Prim].[dbo].[relations]
                 WHERE [relate_type] = 'S'
                 AND obj_id = r.obj_id)

I came up with this other option. Tell me if this is faster in your case. :)

SELECT [obj_id]
FROM [Prim].[dbo].[relations]
GROUP BY [obj_id]
HAVING MAX(CASE WHEN [relate_type] = 'S' THEN 1 ELSE 0 END) = 0

From your question it looks like you want a list of all id's that are missing either one of the values. This will give you a list of [obj_id] With the [relate_type] that is missing (expanding on a previous answer)

SELECT [obj_id], 
 CASE WHEN [relate_type] = 'P' THEN 'S'
END AS [relate type missing]
FROM [Prim].[dbo].[relations] r
WHERE NOT EXISTS(SELECT 1 FROM [Prim].[dbo].[relations]
                 WHERE [relate type] = 'S'
                 AND [obj_id] = r.[obj_id])
UNION              
SELECT [obj_id], 
     CASE WHEN [relate_type] = 'S' THEN 'P'
END AS [relate type missing]
FROM [Prim].[dbo].[relations] r
WHERE NOT EXISTS(SELECT 1 FROM [Prim].[dbo].[relations]
                 WHERE [relate type] = 'P'
                 AND [obj_id] = r.[obj_id])        

You can use either of the two queries to get a list for just missing S or P

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM