SQL-запрос, который получает родителей, которые не имеют определенного значения в дочерней таблице 1 и дочерней таблице 2 - PullRequest
0 голосов
/ 09 января 2019

У меня есть родительская таблица, которая имеет несколько дочерних таблиц. отношения родитель-потомок один-два много. Я должен получить родителей, где их дети не имеют определенных ценностей. Значения в дочерних таблицах различны, поэтому, если значение имеет одна таблица, это не означает, что она находится в других таблицах.

Я пробовал просто обычный INNER JOIN и WHERE NOT IN (коды), но он получил все записи. Код ниже не работает из-за UNION. С родителями UNION, у которых нет кодов в дочерней таблице 2, и с родителями, у которых нет кодов в дочерней таблице 2.

SELECT DISTINCT PAYSLIP.id, PAYSLIP.year, PAYSLIP.month 
FROM (
    SELECT p.id, p.year, p.month
    FROM history_payslip_data p 
    INNER JOIN history_payslip_data_hours pu ON p.id = pu.payslip_id 
    INNER JOIN history_payslip zg ON p.payslip_id = zg.id 
    WHERE NOT EXISTS (
         SELECT 1 
         FROM history_payslip_data_hours pu2
         WHERE p.id = pu2.payslip_id
         AND pu2.code IN ('code1', 'code2', 'code3')
    )
    AND (p.employee_id IN (2) AND p.payslip_type = 'PL' AND zg.locked = TRUE)   
    UNION 
    SELECT p.id, p.year, p.month
    FROM history_payslip_data p 
    INNER JOIN history_payslip_data_other pd ON p.id = pd.payslip_id 
    INNER JOIN history_payslip zg ON p.payslip_id = zg.id 
    WHERE NOT EXISTS (
         SELECT 1 
         FROM history_payslip_data_other pd2
         WHERE p.id = pd2.payslip_id
         AND pd2.code IN ('code1', 'code2', 'code3')
    )
    AND (p.employee_id IN (2) AND p.payslip_type = 'PL' AND zg.locked = TRUE)

) AS PAYSLIP
ORDER BY PAYSLIP.year DESC, PAYSLIP.month DESC; 

Я хочу, чтобы родители не имели кодов ни в одной дочерней таблице.

1 Ответ

0 голосов
/ 10 января 2019

Вы можете сделать это, LEFT JOIN используя CTE для каждого типа дочерней таблицы, для которой вы хотите подавить родительские результаты (я изменил history_payslip.id на payslip_id, чтобы упростить объединения):

WITH hours AS (
SELECT hpd.payslip_id, hpd.employee_id, hpd.year, hpd.month
  FROM history_payslip_data hpd
  --JOIN history_payslip hp USING (payslip_id)
  JOIN history_payslip_data_hours h USING (payslip_id)
 WHERE h.code in ('code1', 'code2', 'code3')
), other AS (
SELECT hpd.payslip_id, hpd.employee_id, hpd.year, hpd.month
  FROM history_payslip_data hpd
  --JOIN history_payslip hp USING (payslip_id)
  JOIN history_payslip_data_other o USING (payslip_id)
 WHERE o.code in ('code1', 'code2', 'code3')
)

SELECT hp.payslip_id as pid, hpd.employee_id as eid, hpd.year, hpd.month
  FROM history_payslip_data hpd
  JOIN history_payslip hp USING (payslip_id)
  LEFT JOIN hours h USING (payslip_id, employee_id)
  LEFT JOIN other o USING (payslip_id, employee_id)
 WHERE hpd.payslip_type = 'PL'
   AND hp.locked IS true
   AND h.payslip_id IS NULL
   AND o.payslip_id IS NULL

Вот как я тестирую это с запросом выше, сохраненным как new-query.sql:

main.sql:

CREATE SCHEMA so54111738;
SET search_path=so54111738;

\i ./tables.ddl
\i ./setup.sql
--\i ./query.sql
\i ./new-query.sql

DROP SCHEMA so54111738 CASCADE;

tables.ddl:

CREATE TABLE history_payslip (
  payslip_id int,
  locked boolean
);

CREATE TABLE history_payslip_data (
  id serial,
  employee_id int,
  payslip_id int,
  payslip_type text,
  year int,
  month int
);

CREATE TABLE history_payslip_data_hours (
  payslip_id int,
  code text
);

CREATE TABLE history_payslip_data_other (
  payslip_id int,
  code text
);

setup.sql:

/* these two groups of inserts represent a payslip plus an hours row that means it should be excluded */
/* payslip 1 for employee 2; hours entry with code 4 */
INSERT INTO history_payslip (payslip_id, locked) VALUES (1, true);
INSERT INTO history_payslip_data (payslip_id, payslip_type, employee_id, year, month) VALUES (1, 'PL', 2, 2018, 12);
INSERT INTO history_payslip_data_hours (payslip_id, code) VALUES (1, 'code4');

/* payslip 1 for employee 2; hours entry with code 3 */
INSERT INTO history_payslip (payslip_id, locked) VALUES (1, true);
INSERT INTO history_payslip_data (payslip_id, payslip_type, employee_id, year, month) VALUES (1, '??', 2, 2018, 12);
INSERT INTO history_payslip_data_hours (payslip_id, code) VALUES (1, 'code3');


/* these two groups of inserts represent a payslip plus an other row that means it should be excluded */
/* payslip 2 for employee 3; other entry with code 4 */
INSERT INTO history_payslip (payslip_id, locked) VALUES (2, true);
INSERT INTO history_payslip_data (payslip_id, payslip_type, employee_id, year, month) VALUES (2, 'PL', 3, 2018, 11);
INSERT INTO history_payslip_data_other (payslip_id, code) VALUES (2, 'code4');

/* payslip 2 for employee 3; other entry with code 3 */
INSERT INTO history_payslip (payslip_id, locked) VALUES (2, true);
INSERT INTO history_payslip_data (payslip_id, payslip_type, employee_id, year, month) VALUES (2, '??', 3, 2018, 11);
INSERT INTO history_payslip_data_other (payslip_id, code) VALUES (2, 'code3');


/* this group of inserts represents a payslip that should be returned because it has no matching hours or other entries */
/* payslip 5 for employee 5; hours entry with code 4 */
INSERT INTO history_payslip (payslip_id, locked) VALUES (5, true);
INSERT INTO history_payslip_data (payslip_id, payslip_type, employee_id, year, month) VALUES (5, 'PL', 5, 2018, 10);
INSERT INTO history_payslip_data_hours (payslip_id, code) VALUES (5, 'code4');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...