sqlrelational-divisionnot-exists

I don't know how division works in SQL SERVER(Using NOT EXISTS... (NOT EXISTS) )


I have 3 tables

PRODUCT          
    ID  -------COUNTRY    
    1   --------Singapore  
    2   --------VietNam   
    3   --------Singapor   
    4   --------Campuchia
RECEIPT
IDPRO -------IDBILL
    1 -------A
    2 -------B
    3 -------A
    3 -------C
    4 -------B
BILL 
   CODE 
    A
    B
    C

The question my teacher ask:list all CODE bought all products from Singapore

This is his answer:

SELECT CODE
FROM BILL B
WHERE NOT EXISTS (
SELECT * FROM PRODUCT P
WHERE COUNTRY='Singagpore' and not exists(
SELECT * FROM RECEIPT R
WHERE B.CODE=R.IDBILL AND P.ID=R.IDPRO))

It works prefectly The result is: A

The problem is that when I run the command line of the subquery, there are no results

SELECT * FROM PRODUCT P
    WHERE COUNTRY='Singagpore' and not exists(
    SELECT * FROM RECEIPT R
    WHERE  P.ID=R.IDPRO)

Suppose the above result is assigned K.

the rest of the command line will be:

SELECT CODE
FROM BILL B
WHERE NOT EXISTS (K)

How can it get any result like my teacher did while it uses empty results as reference?

I have searched for how to use NOT EXISTS, but in division it kinda hard


Solution

  • CREATE TABLE [dbo].[bill] (
        [code]  VARCHAR(100)    NOT NULL    
    );
    
    CREATE TABLE [dbo].[product] (
        [product_id]    INT         NOT NULL,
        [country]   VARCHAR(100)    NOT NULL
    );
    
    CREATE TABLE [dbo].[receipt] (
        [receipt_id]    INT         NOT NULL IDENTITY (1, 1),
        [product_id]    INT         NOT NULL,
        [bill_id]   VARCHAR(100)    NOT NULL
    );
    
    INSERT INTO bill (code) values ('A')
    INSERT INTO bill (code) values ('B')
    INSERT INTO bill (code) values ('C')
    
    INSERT INTO product (product_id, country) values (1,'Singapore')
    INSERT INTO product (product_id, country) values (2,'VietNam')
    INSERT INTO product (product_id, country) values (3,'Singapore')
    INSERT INTO product (product_id, country) values (4,'Campuchia')      
    INSERT INTO receipt (product_id, bill_id) values (1,'A')
    INSERT INTO receipt (product_id, bill_id) values (2,'B')
    INSERT INTO receipt (product_id, bill_id) values (3,'A')
    INSERT INTO receipt (product_id, bill_id) values (3,'C')
    INSERT INTO receipt (product_id, bill_id) values (4,'B')
    

    Returns A:

    SELECT code
    FROM BILL B
    WHERE NOT EXISTS (
        SELECT * FROM PRODUCT P
        WHERE COUNTRY='Singapore' and not exists(
            SELECT * FROM RECEIPT R
            WHERE B.CODE=R.bill_id AND P.product_id=R.product_id))
    

    This is because the code in the NOT EXISTS clause will run for every row in BILL and if the select returns nothing the row will be selected. If the select returns something then it will not be selected. The reverse will happen if you use EXISTS instead of NOT EXISTS. This returns nothing for A, so A will be returned:

    SELECT * FROM PRODUCT P
    WHERE COUNTRY='Singapore' and not exists(
        SELECT * FROM RECEIPT R
        WHERE 'A'=R.bill_id AND P.product_id=R.product_id)
    

    Returns something for B, so B will not be returned:

    SELECT * FROM PRODUCT P
    WHERE COUNTRY='Singapore' and not exists(
        SELECT * FROM RECEIPT R
        WHERE 'B'=R.bill_id AND P.product_id=R.product_id)
    

    Returns something for C, so C will not be returned:

    SELECT * FROM PRODUCT P
    WHERE COUNTRY='Singapore' and not exists(
        SELECT * FROM RECEIPT R
        WHERE 'C'=R.bill_id AND P.product_id=R.product_id)