SQLite User Forum

Compare keys without AND statements?
Login

Compare keys without AND statements?

(1) By cj (sqlitening) on 2022-04-14 12:39:44 [link] [source]

CREATE TABLE IF NOT EXISTS T1 (K1 INTEGER PRIMARY KEY)
CREATE TABLE IF NOT EXISTS T2 (K2 INTEGER PRIMARY KEY)
CREATE TABLE IF NOT EXISTS T3 (K3 INTEGER PRIMARY KEY)
CREATE TABLE IF NOT EXISTS T4 (K4 INTEGER PRIMARY KEY)

SELECT K1,K2,K3,K4 FROM T1,T2,T3,T4 WHERE (K1=K2) AND (K1=K3) AND (K1=K4)

Is there a way to compare keys without all the AND statements?

(2) By Gunter Hick (gunter_hick) on 2022-04-14 13:16:22 in reply to 1 [link] [source]

Maybe you are looking for row values?

https://sqlite.org/rowvalue.html

(3.1) By cj (sqlitening) on 2022-04-14 14:06:56 edited from 3.0 in reply to 2 [source]

Getting no results, but trying.  Thanks!
SELECT FIRST FROM T1,T2 WHERE (T1K1,T2K1)=(?1,?2)"

#INCLUDE ONCE "sqlitening.inc"
FUNCTION PBMAIN AS LONG
 LOCAL sArray() AS STRING
 LOCAL counter AS LONG
 KILL "junk.db3"
 slOpen   "JUNK.DB3","C"
 slexe    "CREATE TABLE IF NOT EXISTS T1 (T1K1 INTEGER PRIMARY KEY,FIRST  TEXT)
 slexe    "CREATE TABLE IF NOT EXISTS T2 (T2K1 INTEGER PRIMARY KEY,LAST   TEXT)
 slexe    "CREATE TABLE IF NOT EXISTS T3 (T3K1 INTEGER PRIMARY KEY,NOTESA TEXT)
 slexe    "CREATE TABLE IF NOT EXISTS T4 (T4K1 INTEGER PRIMARY KEY,NOTESB TEXT)
 FOR counter = 1 TO 4
  slexe    "INSERT INTO T1 VALUES (NULL,'ONE')
  slexe    "INSERT INTO T2 VALUES (NULL,'TWO')
  slexe    "INSERT INTO T3 VALUES (NULL,'NOTEA" + FORMAT$(Counter) + "')"
  slexe    "INSERT INTO T4 VALUES (NULL,'NOTEB" + FORMAT$(counter) + "')"
 NEXT
 slselAry "SELECT FIRST,LAST,NOTESA,NOTESB FROM T1,T2,T3,T4 WHERE (T1K1=T2K1) AND (T1K1=T3K1) AND (T1K1=T4K1)",sArray(),"Q9c"
 ? JOIN$(sArray(),$CR) 'returns 4-rows

 slselAry "SELECT FIRST FROM T1,T2 WHERE (T1K1,T2K1)=(?1,?2)",sArray(),"Q9c"
 ? JOIN$(sArray(),$CR) 'no results, no error

END FUNCTION

(4) By Ryan Smith (cuz) on 2022-04-14 14:06:18 in reply to 1 [link] [source]

I'm afraid there isn't a way to circumvent the comparisons, or get rid of any of them. All have to be tested to ensure the match.

If it is that you just need to get rid of specifically the "AND" words, or need a shorter form of writing it, then certainly row-values is the way.

Example:

SELECT K1,K2,K3,K4 FROM T1,T2,T3,T4 WHERE (K1=K2) AND (K1=K3) AND (K1=K4)
vs.
SELECT K1,K2,K3,K4 FROM T1,T2,T3,T4 WHERE (K1,K1,K1) = (K2,K3,K4)

Note that it still compares all, so you did not save any CPU cycles (in fact, it may take more CPU cycles to do this, I'm not sure), but you did save some characters worth of human typing.

(5) By Gunter Hick (gunter_hick) on 2022-04-14 14:17:44 in reply to 3.1 [link] [source]

Sorry you asked about "comparing keys", which is not the same as "joining tables". 

It is easier to read if you separate the constraints used for joining from the general WHERE clause

SELECT ... FROM t1
JOIN t2 ON (t1k1 = t2K1)
JOIN t3 IN (t1k1 = t3k1)
JOIN t4 ON (t1k1 = t4k1)

Row values might work if you put them in the HAVING clause, but that would be extremely expensive as you would be asking to generate the cartesian product of all the tables and then choose only those with matching keys.

(6.1) By cj (sqlitening) on 2022-04-14 14:18:21 edited from 6.0 in reply to 4 [link] [source]

That was exactly what I was looking for and I like it!

Thank you

(7) By Ryan Smith (cuz) on 2022-04-14 14:33:16 in reply to 3.1 [link] [source]

That should work just fine, what are the parameters that go into ?1 and ?2 ??

Here are examples of the principle working, using your tables:

-- Reference Query:
SELECT FIRST,LAST,NOTESA,NOTESB FROM T1,T2,T3,T4 WHERE (T1K1=T2K1) AND (T1K1=T3K1) AND (T1K1=T4K1);

  -- FIRST| LAST|NOTESA   |NOTESB   
  -- -----|-----|---------|---------
  --  ONE | TWO |NOTEA 1  |NOTEB 1  
  --  ONE | TWO |NOTEA 2  |NOTEB 2  
  --  ONE | TWO |NOTEA 3  |NOTEB 3  
  --  ONE | TWO |NOTEA 4  |NOTEB 4  


-- Select by Row-Values:
SELECT FIRST,LAST,NOTESA,NOTESB FROM T1,T2,T3,T4 WHERE (T1K1, T1K1, T1K1) = (T2K1, T3K1, T4K1);

  -- FIRST| LAST|NOTESA   |NOTESB   
  -- -----|-----|---------|---------
  --  ONE | TWO |NOTEA 1  |NOTEB 1  
  --  ONE | TWO |NOTEA 2  |NOTEB 2  
  --  ONE | TWO |NOTEA 3  |NOTEB 3  
  --  ONE | TWO |NOTEA 4  |NOTEB 4  



-- Select by row-values and parameter specifier:
SELECT FIRST,LAST,NOTESA,NOTESB FROM T1,T2,T3,T4 WHERE (T1K1, T2K1, T3K1) = (T2K1, T3K1, T4K1) AND T1K1 <= 2;

  -- FIRST| LAST|NOTESA   |NOTESB   
  -- -----|-----|---------|---------
  --  ONE | TWO |NOTEA 1  |NOTEB 1  
  --  ONE | TWO |NOTEA 2  |NOTEB 2  

Having said all that, I'm agreeing with Gunter, in joins, specifying the on-clauses for each bind feels like a much more intuitive way and will improve future understanding of the next person to read your code.

(8) By cj (sqlitening) on 2022-04-14 14:43:57 in reply to 5 [link] [source]

I see your point and will use JOIN.  Thanks!

(9.1) By Aask (AAsk1902) on 2022-04-14 16:46:00 edited from 9.0 in reply to 4 [link] [source]

SELECT K1,K2,K3,K4 FROM T1,T2,T3,T4 WHERE (K1,K1,K1) = (K2,K3,K4)

I've never seen a WHERE clause expressed like this! And it works!

I tried:

select * from employees where (lastname,state)=('Adams','AB');
This has values on one side of the equality condition; this works also.

Implicitly, each atomic test is ANDed.Is there a construction or ORing?

Is SQLite's dialect of SQL at this level of detail and including esoteric constructions such as the one above documented somewhere?

(10) By Ryan Smith (cuz) on 2022-04-14 18:35:36 in reply to 9.1 [link] [source]

Of course it is...
See here: sqlite.org/rowvalue.html

It's not very unique or esoteric actually, and also not simply for making more fun WHERE clauses.

Much of its power lies in the ability to ASSIGN values in this way.

Consider a query like:

UPDATE sales SET (customer, item, qty, price) = ('John', 'Waffle', 2, 2.44);

or more elaborately:

UPDATE games SET (publisher, title, release_date) = (
  SELECT A.publisher_name, B.name, B.release
    FROM publishers AS A
    JOIN pub_titles AS B ON B.publisher = A.id
   WHERE A.short_name = 'Konami'
)
 WHERE id = 44;

Prior to row-values, that would have required 3 different queries in SQLite.