[ROZWIĄZANY] Teradata: [Error 3653] [SQLState 21S02] All select-lists do not contain the same number of expressions.

[ROZWIĄZANY] Teradata: [Error 3653] [SQLState 21S02] All select-lists do not contain the same number of expressions.
Photo by Blake Connally on Unsplash

W niniejszym poście wyjaśnię dlaczego napotkaliście błąd [Error 3653] [SQLState 21S02] All select-lists do not contain the same number of expressions, znany także jako Failed [3653 : 21S02] All select-lists do not contain the same number of expressions, przedstawię przyczynę problemu oraz pokażę jak uniknąć błędu w przyszłości.

Problem

Problem może powstać podczas wykonywania operacji UNION, UNION ALL, MINUS oraz INTERSECT. Oto najprostszy sposób na otrzymanie komunikatu błędu używając operacji UNION ALL: 

CREATE TABLE SUBJECT (
SUBJECT_ID INTEGER,
SUBJECT_NAME VARCHAR(100),
LOAD_DATE TIMESTAMP(0));

CREATE TABLE SUBJECT_HISTORY(
SUBJECT_ID INTEGER,
SUBJECT_NAME VARCHAR(100),
LOAD_DATE TIMESTAMP(0),
END_DATE TIMESTAMP(0));

Stworzyliśmy powyżej dwie tabele SUBJECT i SUBJECT_HISTORY, która jest snapshotem danych historycznych i ma dodatkowy atrybut – END_DATE przechowującą datę zamknięcia rekordu. Spróbujmy teraz uzyskać informację o wszystkich pacjentach jakich kiedykolwiek mieliśmy:

SELECT * FROM SUBJECT
UNION ALL
SELECT * FROM SUBJECT_HISTORY;

Nie wygląda to dobrze – dostaliśmy komunikat błędu, ale dlaczego?

Powód

Nie bez przyczyny napisałam, że tabela SUBJECT_HISTORY ma dodatkowy atrybut – END_DATE. W tym momencie tabela SUBJECT ma 3 kolumny, natomiast tabela historyczna ma ich 4. Wykonując w zapytaniu polecenie SELECT *, to tak jakbyśmy napisali:

SELECT SUBJECT_ID, SUBJECT_NAME, LOAD_DATE 
FROM SUBJECT
UNION ALL
SELECT SUBJECT_ID, SUBJECT_NAME, LOAD_DATE, END_DATE 
FROM SUBJECT_HISTORY;

Co Teradata ma zrobić w tym momencie z atrybutem END_DATE? Zdefiniowany jest on tylko w jednym poleceniu SELECT, więc listy naszych atrybutów są różne – i to jest właśnie przyczyna błędu 3653.

Rozwiązanie

Zawsze określaj listę atrybutów zamiast używać SELECT * podczas operacji UNION/ UNION ALL/ MINUS/ INTERSECT

Jeżeli listy atrybutów w tabelach na których wykonujesz jedno z powyższych poleceń są różne, pamiętaj aby zamiast używać polecenia SELECT * podać pełną listę kolumn, których potrzebujesz. Liczba atrybutów w zapytaniu musi być taka sama. Jeśli nie potrzebujesz atrybutu, który zakłóca Twoją listę, możesz po prostu pominąć go w zapytaniu:

SELECT SUBJECT_ID, SUBJECT_NAME, LOAD_DATE 
FROM SUBJECT
UNION ALL
SELECT SUBJECT_ID, SUBJECT_NAME, LOAD_DATE
FROM SUBJECT_HISTORY;

W porządku, ale co jeśli atrybut END_DATE jest dla mnie ważny? Zwłaszcza jeśli łączymy rekordy używając UNION ALL chcielibyśmy wiedzieć, czy jest to nowy czy historyczny rekord. Spójrzmy więc na poniższe obejście problemu:

Work around

Jeśli potrzebujesz wszystkich atrybutów z tabeli, gdzie jest ich więcej, ale nie wiesz jak wtedy użyć poleceń UNION/ UNION ALL/ MINUS bądź INTERSECT, zastąp lukę w danych domyślną wartością bądź NULL’em. Spójrzmy poniżej:

SELECT SUBJECT_ID, SUBJECT_NAME, LOAD_DATE, NULL AS END_DATE
FROM SUBJECT
UNION ALL
SELECT SUBJECT_ID, SUBJECT_NAME, LOAD_DATE, END_DATE 
FROM SUBJECT_HISTORY;

Powyższe zapytanie pozwala nam na otrzymanie informacji o dodatkowym atrybucie END_DATE bez otrzymania błędu 3653.

Jeśli spodobał Ci się ten post to zostaw proszę komentarz poniżej lub udostępnij ten post na swoim Facebook’u, Twitter’ze, LinkedIn lub innej stronie z mediami społecznościowymi.
Dzięki!

Leave a Reply

avatar
  Subscribe  
Powiadom o
Close Menu