SELECT * FROM fleet.node_check_configs WHERE fqdn = 'host-123;`
Start introducing CTE:
WITH result1 AS ( SELECT * FROM fleet.node_check_configs WHERE fqdn = 'host-123')SELECT * FROM reuslt1
Equal to
SELECT * FROM ( SELECT * FROM fleet.node_check_configs WHERE fqdn = 'host-123') AS result1
Incorrect if you:
SELECT * FROM ( (SELECT * FROM fleet.node_check_configs WHERE fqdn = 'host-123' ) AS result1)
You can NOT do: SELECT * FROM ( (subquery) as subquery_result)
You have to: SELECT * FROM (subquery) as subquery_result
Chain (NOTE: There is only one with):
WITHactive_checks AS ( SELECT * FROM fleet.node_check_configs WHERE fqdn = 'host-123' AND deleted_at IS NULL),deleted_checks AS ( SELECT * FROM fleet.node_check_configs WHERE fqdn = 'host-123' AND deleted_at IS NOT NULL)SELECT * FROM active_checks UNION ALL SELECT * FROM deleted_checks
NOTE
There is only ONEWITH, and there is only ONE,
Using CTE for update and writes:
WITH deleted AS ( UPDATE fleet.node_check_configs SET deleted_at = NOW() WHERE fqdn = 'host-123' RETURNING check_id ) SELECT * FROM deleted -- see what was just deleted
So the deleted table should look like:
check_id
---
check-a
check-b
...
One CTE for ‘just sync’
WITHincoming AS ( -- Building a new 'incoming' table with columns: -- check_id, check_name, check_interval, ... -- This the just building the 'incoming' table -- which will be used in follow two steps -- - upsert + mark deleted SELECT * FROM (VALUES ('check-a', 'http check', '30s', ...), ('check-b', 'tcp check' , '15s', ...) ) AS t(check_id, check_name, check_interval, ...) -- the `t` here is meaningless, you can change it to anything),upserted AS ( -- Using 'incoming', if not exist, insert, if already exist, update INSERT INTO fleet.node_check_configs (fqdn, check_id, check_name, ...) SELECT 'host-123' check_id, check_name, ... FROM incoming -- 'ON CONFLICT + excluded' -> here is the logic for 'how to handle conflict' -- i.e. the update logic ON CONFLICT (fqdn, check_id) DO UPDATE SET check_name = excluded.check_name, ... <many other columns, we need to explain what to do for each of them>),unreported AS ( UPDATE fleet.node_check_configs set deleted_at = NOW() WHERE fqdn = 'host-123' AND deleted_at IS NULL AND NOT EXISTS ( SELECT 1 FROM incoming -- using `SELECT 1` here as we don't need the column values for the 'matched items' WHERE incoming.check_id = node_check_configs.check_id )) -- no comma here!SELECT 1 -- yep, we basically did everything in CTE, but we still need to make this a complete query...so add this.
You can't
WITH incoming AS (VALUES ('check-a', 'http check', '30s', ...), ('check-b', 'tcp check' ,'15s' ...))),
This won’t work. In the CTE you must use complete SELETE statement (or some other statement I guess?), you can’t use VALUES.
But you can
WITH incoming(check_id, check_name, check_interval) AS ( VALUES ('check-a', 'http check', '30s'...), ('check-b', 'tcp check', '15s'...),)
For the part of:
UPDATE fleet.node_check_configs set deleted_at = NOW() WHERE fqdn = 'host-123' AND deleted_at IS NULL AND NOT EXISTS ( SELECT 1 FROM incoming -- using `SELECT 1` here as we don't need the column values for the 'matched items' WHERE incoming.check_id = node_check_configs.check_id )
It can also be written as:
UPDATE fleet.node_check_configs set deleted_at = NOW() WHERE fqdn = 'host-123' AND deleted_at IS NULL AND node_check_configs.check_id NOT IN ( SELECT check_id FROM incoming )
→ This one is much easier to understand.
For the NOT EXISTS, see NOT EXISTS, generally, just 背下来.
Appendix
Insert
Most basic:
INSERT INTO users (name, age) VALUES ('alice', 25)
But VALUES can be replaced by SELECT
Not the other way around
Not all the places of ‘SELECT’ can be replaced by ‘VALUES’
VALUES is just hardcoded literal data. SELECT can do everything VALUES can (by selecting constants), plus it can also pull from tables, CTEs, join things, filter, transform, etc.
With SELECT:
INSERT INTO users (name, age) SELECT name, age FROM new_users
NOT EXISTS
Just always remember this pattern:
SELECT name FROM students WHERE NOT EXISTS ( SELECT 1 FROM grades WHERE grades.student_id = students.id )
NOT EXISTS (SELECT 1 FROM ... WHERE ...)IS the pattern. There’s no simpler form — that’s just how the syntax works.
就是背下来就是了
Always in a WHERE statement
NOT EXISTS basically always used in a WHERE state.
Select * FROM students WHERE NOT EXISTS (...)UPDATE students SET status = "inactive" WHERE NOT EXISTS (...)DELETE FROM students WHERE NOT EXISTS (...)