SQL SERVER FIND ROWS that dont have values in another table

wpx232ag  于 2023-03-07  发布在  SQL Server
关注(0)|答案(3)|浏览(179)

i have 3 tables with one to many relation {Downloads , TagNames, File_Tag}

the download table Like
| ID | File | _modifieddate |
| ------------ | ------------ | ------------ |
| 1 | FILE1.ZIP | 2/1/2023 |
| 2 | FILE2.ZIP | 3/1/2023 |
| 3 | FILE3.ZIP | 4/1/2023 |
| 4 | FILE4.ZIP | 5/1/2023 |

the TagNames table Like

IDTagName
1system
2pics
3framework
4compressed
5info

the File_Tag table Like

IDFileIDTagID
111
213
314
424
522
631
734
845
944

what i want all downloads table records that dont have 'pics' or 'info' tag related to it

i tried

select * from (
SELECT Downloads._modifieddate, Downloads.File, Downloads.ID, ROW_NUMBER() over ( ORDER BY Downloads._modifieddate DESC ) AS aa FROM
 TagNames INNER JOIN File_Tag ON TagNames.ID = File_Tag.TagID INNER JOIN  Downloads ON File_Tag.FileID = Downloads.ID WHERE  (TagNames.TagName <> 'pics' ) and (TagNames.TagName <> 'info' )) as product

the row_number for paging purpose but it return file2.zip because it has another row with compressed tag and it give me duplicates for every tag related to the file

what i expect
| ID | File | _modifieddate |
| ------------ | ------------ | ------------ |
| 1 | FILE1.ZIP | 2/1/2023 |
| 3 | FILE3.ZIP | 4/1/2023 |

wj8zmpe1

wj8zmpe11#

You need an anti-join, which in SQL is normally done using a NOT EXISTS

SELECT
  d.ID
  d.File
  d._modifieddate
FROM Download d
WHERE NOT EXISTS (SELECT 1
    FROM File_Tag ft
    JOIN TagNames t ON t.ID = ft.TagID
    WHERE ft.FileID = d.ID    -- join condition
      AND t.TagName IN ('pics', 'info')
);

Make sure you have the join condition inside the subquery, or you will get incorrect results.

If you want Downloads which do not have both tags, but don't mind if they only have one, then use relational division. There are a number of ways to do this, here is a simple one:

SELECT
  d.ID
  d.File
  d._modifieddate
FROM Download d
WHERE NOT EXISTS (SELECT 1
    FROM File_Tag ft
    JOIN TagNames t ON t.ID = ft.TagID
    WHERE ft.FileID = d.ID    -- join condition
      AND t.TagName IN ('pics', 'info')
    HAVING COUNT(*) = 2    -- NEW!!
);
wz1wpwve

wz1wpwve2#

select d.id,d.file, d.modifieddate
from downloads as d
where not exists
(
  select 1 
  from file_tag as ftag
  join TagNames as tag on ftag.tagid=tag.id
  where tag.TagName in('pics','info')and d.id=ftag.fileid
)

May be something like this

7fyelxc5

7fyelxc53#

What you want is something like:

select * from downloads where id not in (select fileid from file_tag where tagid in (select id from TagNames where TagName in ('pics','info')))

相关问题