\set ECHO none
\pset format unaligned

CREATE TABLE result_formula AS SELECT
  *, sr_formula(provenance(),'personnel_name') AS formula FROM (
    (SELECT DISTINCT city FROM personnel)
  EXCEPT
    (SELECT p1.city
     FROM personnel p1, personnel p2
     WHERE p1.city = p2.city AND p1.id < p2.id
     GROUP BY p1.city)
  ) t
ORDER BY city;

SELECT remove_provenance('result_formula');
SELECT city, replace(formula,'(Dave ⊗ Nancy) ⊕ (Dave ⊗ Magdalen)','(Dave ⊗ Magdalen) ⊕ (Dave ⊗ Nancy)') AS formula FROM result_formula;

DROP TABLE result_formula;

CREATE TABLE result_formula AS SELECT
  *, sr_formula(provenance(),'personnel_name') AS formula FROM (
    (SELECT city
     FROM personnel
     WHERE FALSE)
  EXCEPT
    (SELECT city
     FROM personnel p)
  ) t
ORDER BY city;

SELECT remove_provenance('result_formula');
SELECT * FROM result_formula;

DROP TABLE result_formula;

-- EXCEPT ALL implements the NOT-IN semantics of the ICDE 2026 paper (§IV-B):
--   ⟪q1 − q2⟫ = {{ (u, α ⊖ ⊕_{β:(u,β)∈q2} β) | (u,α) ∈ q1 }}
-- The sum ⊕β ranges over ALL right tuples equal to u (the right arm is grouped
-- first), and every left tuple is kept.  With a duplicate-valued right arm this
-- differs from the old per-match ⊕(α⊖βi).
CREATE TABLE ea_a(x int);
CREATE TABLE ea_b(x int);
INSERT INTO ea_a VALUES (1);
INSERT INTO ea_b VALUES (1),(1);
SELECT add_provenance('ea_a');
SELECT add_provenance('ea_b');
DO $$ BEGIN
  PERFORM set_prob(provsql, 0.5) FROM ea_a;
  PERFORM set_prob(provsql, 0.5) FROM ea_b;
END $$;

-- One left row, two equal right rows: NOT-IN keeps one row with provenance
-- a ⊖ (b1 ⊕ b2), so P = P(a ∧ ¬b1 ∧ ¬b2) = 0.5^3 = 0.125 (not the old 0.375),
-- and EXCEPT ALL returns exactly one row (not two).
CREATE TABLE ea_all AS
  SELECT round(probability_evaluate(provenance())::numeric, 4) AS p
  FROM (SELECT x FROM ea_a EXCEPT ALL SELECT x FROM ea_b) t;
SELECT remove_provenance('ea_all');
SELECT count(*) AS n_rows, min(p) AS p_except_all FROM ea_all;
DROP TABLE ea_all;

-- EXCEPT (set semantics ε(q1−q2)) coincides here (single left value).
CREATE TABLE ea_set AS
  SELECT round(probability_evaluate(provenance())::numeric, 4) AS p
  FROM (SELECT x FROM ea_a EXCEPT SELECT x FROM ea_b) t;
SELECT remove_provenance('ea_set');
SELECT count(*) AS n_rows, min(p) AS p_except FROM ea_set;
DROP TABLE ea_set;

DROP TABLE ea_a;
DROP TABLE ea_b;
