невозможно присоединиться к вложенному запросу

#sql #postgresql #subquery #max #left-join

#sql #postgresql #вложенный запрос #макс #левое соединение

Вопрос:

извиняюсь за название вопроса, я не был уверен, как описать эту проблему :

возьмите следующий CTE

 WITH cte_form_answers AS (
SELECT fa.id
,      MAX(CASE WHEN fa.question = 'contact' THEN fa.answer END) AS ContactMethod
FROM formanswers fa
GROUP BY fa.id)
  

 SELECT * FROM cte_form_answers 
id | ContactMethod
0  | Mobile
1  | Landline
  

и следующая таблица

 SELECT id, ContactMethod, Contact from contacts
id | ContactMethod | Contact
0  | Mobile        | xxxx-xxx-xxx
0  | Email         | xxx@email.com
1  | Landline      | xxxx-xxxx-xxx
1  | Mobile        | xxx-xxx-xxxx
  

Я пытаюсь присоединиться, используя contatMethod из моего в моем CTE в таблицу контактов

Моя собственная попытка была :

 WITH cte_form_answers AS (SELECT fa.id
,      MAX(CASE WHEN fa.question = 'contact' THEN fa.answer END) AS ContactMethod
FROM formanswers fa
LEFT JOIN contacts c 
ON   c.id = fa.id 
AND  c.ContactMethod = ( SELECT fa1.id, MAX(CASE WHEN fa1.question = 'contact' THEN fa1.answer END) 
                         FROM formanswers fa1 GROUP BY fa1.ID 
                         GROUP BY fa.id)
  

что приводит к ошибке SQL Error [42601]: ERROR: subquery must return only one column Position: 722

Может кто-нибудь подсказать мне, как правильно это выполнить?

просто чтобы отметить, что таблица контактов представляет собой медленно меняющееся измерение, поэтому в ней есть end_date столбец, который я также фильтрую в соединении, но я чувствую, что это не имеет значения для этого вопроса.

Ответ №1:

Вам нужно присоединиться к другой области, в которой вы агрегируете. Например:

 WITH cte_form_answers AS (
    SELECT fa.id,
        MAX(fa.answer) FILTER(WHERE fa.question = 'contact') AS ContactMethod
    FROM formanswers fa
    GROUP BY fa.id
)
SELECT *
FROM cte_form_answers a
LEFT JOIN contacts c ON c.id = fa.id AND c.ContactMethod = a.ContactMethod
  

Или использование другого CTE, если вы предпочитаете:

 WITH 
    cte_form_answers AS (
        SELECT fa.id,
            MAX(fa.answer) FILTER(WHERE fa.question = 'contact') AS ContactMethod
        FROM formanswers fa
        GROUP BY fa.id
    ),
    cte_form_contact AS (       
        SELECT *
        FROM cte_form_answers a
        LEFT JOIN contacts c ON c.id = fa.id AND c.ContactMethod = a.ContactMethod
    )
SELECT * FROM cte_form_contact
  

Комментарии:

1. Спасибо, я неправильно думал, чтобы решить это в рамках одного CTE? также я заметил, что вы используете filter вместо my CASE WHEN , из-за предпочтений или есть прирост производительности?

2. @Manaskin: вам нужна другая область — либо CTE, либо подзапрос. Я не знаю, есть ли преимущество в производительности при использовании этого filter() предложения. Мне это нравится, потому что это аккуратнее (и это стандартный SQL тоже).

3. Спасибо, GMB, ценю это