Domanda

enter image description here

SELECT DISTINCT cname
FROM account AS cust_account
WHERE NOT EXISTS ( SELECT type
                   FROM account
                   EXCEPT
                   SELECT type
                   FROM account
                   WHERE account.cname = cust_account.cname )

Can someone please explain step-by-step how the query produces the result required by the question? I am just learning about NOT EXISTS and am not sure what values it takes from the parenthesis and where the WHERE clause belongs with.

This is sample table account enter image description here

È stato utile?

Soluzione

There are three separate parts to the query. I'll label them so I can reference each more clearly:

SELECT DISTINCT cname             -- Part A
FROM account AS cust_account
WHERE NOT EXISTS ( SELECT type    -- Part B
                   FROM account
                   EXCEPT
                   SELECT type    -- Part C
                   FROM account
                   WHERE account.cname = cust_account.cname )

First the inner query. Part C lists all type values for account rows owned by the customer currently being considered by the outer query (Part A). Conceptually you can think of the DBMS reading all rows that match the outer query then stepping through them one at a time. For each outer row it executes the inner query. (In reality likely something more time-efficient happens but it will be logically equivalent to this.)

Part C is sometimes called a correlated sub-query because it is matched (correlated) with a value coming from the outer query. In this case it is matching on cname. It is the WHERE clause that tells the DBMS to match Part C to Part A. cust_account is an alias defined in the outer query. Because a single table - account - is used three times in the statement the alias allows us to specify exactly which of these three we want to reference. It is the alias which allows us to say "match Part C to Part A."

Part B lists all type values from table account. This part has no WHERE so it lists all accounts for all users, not just the one currently being considered by the outer query. This part is not correlated.

The EXCEPT takes the results of the query above it (Part B) and removes those rows which occur in the query below it (Part C). Since Part B is "all types that are in the database" and Part C is "all types the current cname owns" then "B except C" is "all types except those which the current cname owns." If we have a list of all types, and we remove those which the cname owns, what is left is those types which the cname does not own. So if the inner query has any rows (for the current cname) we know there is at least one type of account that cname does not own.

EXISTS() returns true if the inner query has row(s). So NOT EXISTS() returns true if the inner query is empty. As we have just shown, it will be empty if the current cname owns all types of accounts. So the outer query lists all cname which have all types of account - as requested in the problem.

Altri suggerimenti

You have two tables in this

customers(cname)
accounts(cname,type)

I think you want this. You want to SELECT all cusotmers that have a matching account. It doesn't make sense to negate everything. And it doesn't make sense to say "every type of account." Because types here are values, and

  • it doesn't make sense to have a customer with more than one value.
  • it the question means any account, it's easier to select on the join condition itself in the exists,

I think it's a bad question.

SELECT cname
FROM customers AS c
WHERE EXISTS (
  SELECT 1
  FROM accounts AS a
  WHERE a.cname = c.cname
);

It also doesn't make sense to use DISTINCT cname there unless you know that there can be duplicate names AND if there were duplicate names and you used DISTINCT then you're no longer talking about customers -- just the values of their names in a (unique) set.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a dba.stackexchange
scroll top