SQL select join: czy możliwe jest prefiksowanie wszystkich kolumn jako „prefiks. *”?

206

Zastanawiam się, czy jest to możliwe w SQL. Załóżmy, że masz dwie tabele A i B i dokonujesz wyboru w tabeli A i dołączasz do tabeli B:

SELECT a.*, b.* FROM TABLE_A a JOIN TABLE_B b USING (some_id);

Jeśli tabela A ma kolumny „a_id”, „name” i „some_id”, a tabela B ma „b_id”, „name” i „some_id”, zapytanie zwróci kolumny „a_id”, „name”, „some_id ”,„ b_id ”,„ name ”,„ some_id ”. Czy jest jakiś sposób na prefiks nazw kolumn tabeli B bez wyszczególnienia każdej kolumny osobno? Odpowiednik tego:

SELECT a.*, b.b_id as 'b.b_id', b.name as 'b.name', b.some_id as 'b.some_id'
FROM TABLE_A a JOIN TABLE_B b USING (some_id);

Ale, jak wspomniano, bez wyświetlania każdej kolumny, więc coś takiego:

SELECT a.*, b.* as 'b.*'
FROM TABLE_A a JOIN TABLE_B b USING (some_id);

Zasadniczo coś do powiedzenia: „poprzedź każdą kolumnę zwróconą przez b. * Słowem„ coś ””. Czy to możliwe, czy nie mam szczęścia?

Z góry dziękuje za twoją pomoc!

EDYCJA: rada dotycząca nieużywania SELECT * i tak dalej jest poprawna rada, ale nie ma znaczenia w moim kontekście, więc proszę trzymać się omawianego problemu - czy można dodać prefiks (stałą określoną w zapytaniu SQL) do wszystkich nazwy kolumn tabeli w złączeniu?

EDYCJA: moim ostatecznym celem jest móc wykonać WYBÓR * na dwóch tabelach z łączeniem i móc stwierdzić na podstawie nazw kolumn, które otrzymuję w moim zestawie wyników, które kolumny pochodzą z tabeli A i które kolumny przyszły z tabeli B. Ponownie nie chcę wymieniać kolumn indywidualnie, muszę mieć możliwość WYBIERZ *.

Foxdonut
źródło
Czego dokładnie oczekujesz wynik zapytania? Jestem zdezorientowany
GregD
GregD: Chcę, aby wszystkie nazwy kolumn wychodzące z b. * Były poprzedzone pewną stałą, którą określam. Na przykład zamiast „nazwa” i „liczba” chcę określić, powiedzmy, prefiks „special_” i uzyskać „special_name” i „special_number”. Ale nie chcę tego robić dla każdej kolumny osobno.
foxdonut
6
Kiedy robię szybkie WYBIERZ, aby zobaczyć kolumny z wielu tabel, czasami wybieram „AAAAA”, A. *, „BBBBB”, B. * Z Tabeli A JAK DOŁĄCZYĆ Tabela B AS B NA A.ID = B.ID, aby I podczas skanowania wzdłuż wierszy przynajmniej identyfikator tabeli
Kristen
Możliwy duplikat: stackoverflow.com/questions/2595068/…
Andrioid

Odpowiedzi:

35

Widzę tutaj dwie możliwe sytuacje. Po pierwsze, chcesz wiedzieć, czy istnieje do tego standard SQL, którego możesz ogólnie używać bez względu na bazę danych. Nie, nie ma. Po drugie, chcesz wiedzieć o konkretnym produkcie dbms. Następnie musisz go zidentyfikować. Ale wyobrażam sobie, że najbardziej prawdopodobną odpowiedzią jest to, że otrzymasz coś takiego jak „a.id, b.id”, ponieważ w ten sposób musisz zidentyfikować kolumny w wyrażeniu SQL. A najprostszym sposobem, aby dowiedzieć się, jakie są ustawienia domyślne, jest przesłanie takiego zapytania i sprawdzenie, co otrzymasz. Jeśli chcesz określić, jaki prefiks występuje przed kropką, możesz na przykład użyć polecenia „WYBIERZ * Z AS my_alias”.

dkretz
źródło
11
Nie jestem pewien, jak to odpowiada na twoje pytanie. Używam MS SQL Server i dodawanie aliasu po tym, jak nazwa tabeli nie dołącza aliasu do nazw kolumn w zestawie wyników.
paiego,
74

Wygląda na to, że odpowiedź na twoje pytanie brzmi „nie”, jednak jednym z możliwych hacków jest przypisanie fikcyjnej kolumny do oddzielenia każdej nowej tabeli. Działa to szczególnie dobrze, jeśli przeglądasz zestaw wyników dla listy kolumn w języku skryptowym, takim jak Python lub PHP.

SELECT '' as table1_dummy, table1.*, '' as table2_dummy, table2.*, '' as table3_dummy, table3.* FROM table1
JOIN table2 ON table2.table1id = table1.id
JOIN table3 ON table3.table1id = table1.id

Zdaję sobie sprawę, że to nie odpowiada dokładnie na twoje pytanie, ale jeśli jesteś programistą, jest to świetny sposób na oddzielenie tabel ze zduplikowanymi nazwami kolumn. Mam nadzieję, że to komuś pomoże.

Wayne Bryan
źródło
24

Całkowicie rozumiem, dlaczego jest to konieczne - przynajmniej dla mnie jest to przydatne podczas szybkiego prototypowania, gdy istnieje wiele tabel do połączenia, w tym wiele połączeń wewnętrznych. Gdy tylko nazwa kolumny będzie taka sama w drugiej dzikiej karcie pola „Jointable. *”, Wartości pól w głównej tabeli zostaną zastąpione wartościami Jointable. Podatne na błędy, frustrujące i naruszające SUSZENIE, gdy trzeba ręcznie określać pola tabeli za pomocą aliasów w kółko ...

Oto funkcja PHP (Wordpress), która pozwala to osiągnąć poprzez generowanie kodu wraz z przykładem jego użycia. W tym przykładzie jest on używany do szybkiego generowania niestandardowego zapytania, które zapewni pola pokrewnego wpisu wordpress, do którego odwołuje się zaawansowane pole niestandardowych pól .

function prefixed_table_fields_wildcard($table, $alias)
{
    global $wpdb;
    $columns = $wpdb->get_results("SHOW COLUMNS FROM $table", ARRAY_A);

    $field_names = array();
    foreach ($columns as $column)
    {
        $field_names[] = $column["Field"];
    }
    $prefixed = array();
    foreach ($field_names as $field_name)
    {
        $prefixed[] = "`{$alias}`.`{$field_name}` AS `{$alias}.{$field_name}`";
    }

    return implode(", ", $prefixed);
}

function test_prefixed_table_fields_wildcard()
{
    global $wpdb;

    $query = "
    SELECT
        " . prefixed_table_fields_wildcard($wpdb->posts, 'campaigns') . ",
        " . prefixed_table_fields_wildcard($wpdb->posts, 'venues') . "
        FROM $wpdb->posts AS campaigns
    LEFT JOIN $wpdb->postmeta meta1 ON (meta1.meta_key = 'venue' AND campaigns.ID = meta1.post_id)
    LEFT JOIN $wpdb->posts venues ON (venues.post_status = 'publish' AND venues.post_type = 'venue' AND venues.ID = meta1.meta_value)
    WHERE 1
    AND campaigns.post_status = 'publish'
    AND campaigns.post_type = 'campaign'
    LIMIT 1
    ";

    echo "<pre>$query</pre>";

    $posts = $wpdb->get_results($query, OBJECT);

    echo "<pre>";
    print_r($posts);
    echo "</pre>";
}

Wyjście:

SELECT
    `campaigns`.`ID` AS `campaigns.ID`, `campaigns`.`post_author` AS `campaigns.post_author`, `campaigns`.`post_date` AS `campaigns.post_date`, `campaigns`.`post_date_gmt` AS `campaigns.post_date_gmt`, `campaigns`.`post_content` AS `campaigns.post_content`, `campaigns`.`post_title` AS `campaigns.post_title`, `campaigns`.`post_excerpt` AS `campaigns.post_excerpt`, `campaigns`.`post_status` AS `campaigns.post_status`, `campaigns`.`comment_status` AS `campaigns.comment_status`, `campaigns`.`ping_status` AS `campaigns.ping_status`, `campaigns`.`post_password` AS `campaigns.post_password`, `campaigns`.`post_name` AS `campaigns.post_name`, `campaigns`.`to_ping` AS `campaigns.to_ping`, `campaigns`.`pinged` AS `campaigns.pinged`, `campaigns`.`post_modified` AS `campaigns.post_modified`, `campaigns`.`post_modified_gmt` AS `campaigns.post_modified_gmt`, `campaigns`.`post_content_filtered` AS `campaigns.post_content_filtered`, `campaigns`.`post_parent` AS `campaigns.post_parent`, `campaigns`.`guid` AS `campaigns.guid`, `campaigns`.`menu_order` AS `campaigns.menu_order`, `campaigns`.`post_type` AS `campaigns.post_type`, `campaigns`.`post_mime_type` AS `campaigns.post_mime_type`, `campaigns`.`comment_count` AS `campaigns.comment_count`,
    `venues`.`ID` AS `venues.ID`, `venues`.`post_author` AS `venues.post_author`, `venues`.`post_date` AS `venues.post_date`, `venues`.`post_date_gmt` AS `venues.post_date_gmt`, `venues`.`post_content` AS `venues.post_content`, `venues`.`post_title` AS `venues.post_title`, `venues`.`post_excerpt` AS `venues.post_excerpt`, `venues`.`post_status` AS `venues.post_status`, `venues`.`comment_status` AS `venues.comment_status`, `venues`.`ping_status` AS `venues.ping_status`, `venues`.`post_password` AS `venues.post_password`, `venues`.`post_name` AS `venues.post_name`, `venues`.`to_ping` AS `venues.to_ping`, `venues`.`pinged` AS `venues.pinged`, `venues`.`post_modified` AS `venues.post_modified`, `venues`.`post_modified_gmt` AS `venues.post_modified_gmt`, `venues`.`post_content_filtered` AS `venues.post_content_filtered`, `venues`.`post_parent` AS `venues.post_parent`, `venues`.`guid` AS `venues.guid`, `venues`.`menu_order` AS `venues.menu_order`, `venues`.`post_type` AS `venues.post_type`, `venues`.`post_mime_type` AS `venues.post_mime_type`, `venues`.`comment_count` AS `venues.comment_count`
    FROM wp_posts AS campaigns
LEFT JOIN wp_postmeta meta1 ON (meta1.meta_key = 'venue' AND campaigns.ID = meta1.post_id)
LEFT JOIN wp_posts venues ON (venues.post_status = 'publish' AND venues.post_type = 'venue' AND venues.ID = meta1.meta_value)
WHERE 1
AND campaigns.post_status = 'publish'
AND campaigns.post_type = 'campaign'
LIMIT 1

Array
(
    [0] => stdClass Object
        (
            [campaigns.ID] => 33
            [campaigns.post_author] => 2
            [campaigns.post_date] => 2012-01-16 19:19:10
            [campaigns.post_date_gmt] => 2012-01-16 19:19:10
            [campaigns.post_content] => Lorem ipsum
            [campaigns.post_title] => Lorem ipsum
            [campaigns.post_excerpt] => 
            [campaigns.post_status] => publish
            [campaigns.comment_status] => closed
            [campaigns.ping_status] => closed
            [campaigns.post_password] => 
            [campaigns.post_name] => lorem-ipsum
            [campaigns.to_ping] => 
            [campaigns.pinged] => 
            [campaigns.post_modified] => 2012-01-16 21:01:55
            [campaigns.post_modified_gmt] => 2012-01-16 21:01:55
            [campaigns.post_content_filtered] => 
            [campaigns.post_parent] => 0
            [campaigns.guid] => http://example.com/?p=33
            [campaigns.menu_order] => 0
            [campaigns.post_type] => campaign
            [campaigns.post_mime_type] => 
            [campaigns.comment_count] => 0
            [venues.ID] => 84
            [venues.post_author] => 2
            [venues.post_date] => 2012-01-16 20:12:05
            [venues.post_date_gmt] => 2012-01-16 20:12:05
            [venues.post_content] => Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
            [venues.post_title] => Lorem ipsum venue
            [venues.post_excerpt] => 
            [venues.post_status] => publish
            [venues.comment_status] => closed
            [venues.ping_status] => closed
            [venues.post_password] => 
            [venues.post_name] => lorem-ipsum-venue
            [venues.to_ping] => 
            [venues.pinged] => 
            [venues.post_modified] => 2012-01-16 20:53:37
            [venues.post_modified_gmt] => 2012-01-16 20:53:37
            [venues.post_content_filtered] => 
            [venues.post_parent] => 0
            [venues.guid] => http://example.com/?p=84
            [venues.menu_order] => 0
            [venues.post_type] => venue
            [venues.post_mime_type] => 
            [venues.comment_count] => 0
        )
)
Motin
źródło
13

Jedyną znaną mi bazą danych, która to robi, jest SQLite, w zależności od ustawień konfigurowanych za pomocą PRAGMA full_column_namesi PRAGMA short_column_names. Zobacz http://www.sqlite.org/pragma.html

W przeciwnym razie wszystko, co mogę polecić, to pobrać kolumny w zestawie wyników według pozycji porządkowej zamiast nazwy kolumny, jeśli wpisanie nazw kolumn w zapytaniu jest zbyt trudne.

To dobry przykład tego, dlaczego stosowanie złej praktyki jest takieSELECT * - ponieważ w końcu i tak będziesz musiał wpisać wszystkie nazwy kolumn.

Rozumiem potrzebę obsługi kolumn, które mogą zmienić nazwę lub pozycję, ale używanie symboli wieloznacznych sprawia, że ​​jest to trudniejsze , a nie łatwiejsze.

Bill Karwin
źródło
2
Należy zauważyć, że zarówno full_column_namesi short_column_namesprzestarzałe w SQLite.
isanae
6

Jestem w pewnym sensie tą samą łodzią co OP - mam dziesiątki pól z 3 różnych tabel, do których dołączam, z których niektóre mają tę samą nazwę (np. Identyfikator, nazwa itp.). Nie chcę wymieniać każdego pola, więc moim rozwiązaniem było aliasowanie pól o wspólnej nazwie i użycie opcji select * dla tych, które mają unikalną nazwę.

Na przykład :

tabela a: identyfikator, nazwa, pole 1, pole 2 ...

tabela b: identyfikator, nazwa, pole 3, pole 4 ...

wybierz a.id jako aID, a.name jako aName, a. *, b. id jako bID, b. nazwa jak bName, b. * .....

Uzyskując dostęp do wyników, używam pseudonimów dla tych pól i ignoruję nazwy „oryginalne”.

Może nie najlepsze rozwiązanie, ale działa dla mnie .... używam mysql


źródło
5

Różne produkty baz danych dają różne odpowiedzi; ale narażasz się na zranienie, jeśli posuniesz się tak daleko. O wiele lepiej jest wybrać kolumny, które chcesz, i nadać im własne aliasy, aby tożsamość każdej kolumny była krystalicznie czysta, a wyniki można odróżnić.

dkretz
źródło
1
Podkreślono, ale mój cel tutaj jest czymś bardzo ogólnym, więc brak jasności nie stanowi problemu. W rzeczywistości bycie konkretnym stanowiłoby problem.
foxdonut
Zobacz dalsze przesyłanie poniżej. Czy możesz skorzystać z dot.notation, który prawdopodobnie dostaniesz domyślnie?
dkretz
Jest to ważne dla czytelności. Miałem nadzieję, że zrobię to teraz, ponieważ mam zlikwidowany proces CTE. dawny. CTE_A -> CTE_B -> CTE_C -> CTE_D -> select / insert Nie ma potrzeby określania kolumn, które chcę, dopóki ostateczna instrukcja select i wydajność nie będą brane pod uwagę.
ThomasRones
5

To pytanie jest bardzo przydatne w praktyce. Konieczne jest jedynie wyszczególnienie wszystkich wyraźnych kolumn w oprogramowaniu, w których zwracasz szczególną uwagę na wszystkie warunki.

Wyobraź sobie, że podczas debugowania lub spróbuj użyć DBMS jako codziennego narzędzia biurowego, zamiast czegoś, co można modyfikować, implementacji abstrakcyjnej infrastruktury określonego programisty, musimy napisać dużo SQL. Scenariusz można znaleźć wszędzie, np. Konwersja bazy danych, migracja, administracja itp. Większość tych SQL-ów zostanie wykonana tylko raz i nigdy więcej nie będzie używana, ponieważ nazwy każdej kolumny to tylko strata czasu. I nie zapominaj, że wynalazek SQL nie jest przeznaczony wyłącznie dla programistów.

Zwykle utworzę widok narzędzia z prefiksem nazw kolumn, tutaj jest funkcja w pl / pgsql, nie jest to łatwe, ale można przekonwertować ją na inne języki procedur.

-- Create alias-view for specific table.

create or replace function mkaview(schema varchar, tab varchar, prefix varchar)
    returns table(orig varchar, alias varchar) as $$
declare
    qtab varchar;
    qview varchar;
    qcol varchar;
    qacol varchar;
    v record;
    sql varchar;
    len int;
begin
    qtab := '"' || schema || '"."' || tab || '"';
    qview := '"' || schema || '"."av' || prefix || tab || '"';
    sql := 'create view ' || qview || ' as select';

    for v in select * from information_schema.columns
            where table_schema = schema and table_name = tab
    loop
        qcol := '"' || v.column_name || '"';
        qacol := '"' || prefix || v.column_name || '"';

        sql := sql || ' ' || qcol || ' as ' || qacol;
        sql := sql || ', ';

        return query select qcol::varchar, qacol::varchar;
    end loop;

    len := length(sql);
    sql := left(sql, len - 2); -- trim the trailing ', '.
    sql := sql || ' from ' || qtab;

    raise info 'Execute SQL: %', sql;
    execute sql;
end
$$ language plpgsql;

Przykłady:

-- This will create a view "avp_person" with "p_" prefix to all column names.
select * from mkaview('public', 'person', 'p_');

select * from avp_person;
Xiè Jìléi
źródło
3

Całkowicie rozumiem twój problem związany ze zduplikowanymi nazwami pól.

Potrzebowałem tego też, dopóki nie zakodowałem własnej funkcji, aby ją rozwiązać. Jeśli używasz PHP, możesz go użyć lub napisać kod w języku, którego używasz, jeśli masz następujące możliwości.

Sztuczka polega na tym, że mysql_field_table()zwraca nazwę tabeli i mysql_field_name()pole dla każdego wiersza w wyniku, jeśli jest on dostępny, mysql_num_fields()dzięki czemu można mieszać je w nowej tablicy.

To poprzedza wszystkie kolumny;)

Pozdrowienia,

function mysql_rows_with_columns($query) {
    $result = mysql_query($query);
    if (!$result) return false; // mysql_error() could be used outside
    $fields = mysql_num_fields($result);
    $rows = array();
    while ($row = mysql_fetch_row($result)) { 
        $newRow = array();
        for ($i=0; $i<$fields; $i++) {
            $table = mysql_field_table($result, $i);
            $name = mysql_field_name($result, $i);
            $newRow[$table . "." . $name] = $row[$i];
        }
        $rows[] = $newRow;
    }
    mysql_free_result($result);
    return $rows;
}
axelbrz
źródło
2

Nie ma na to standardu SQL.

Jednak w przypadku generowania kodu (na żądanie, gdy tabele są tworzone, zmieniane lub w czasie wykonywania), można to zrobić dość łatwo:

CREATE TABLE [dbo].[stackoverflow_329931_a](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [col2] [nchar](10) NULL,
    [col3] [nchar](10) NULL,
    [col4] [nchar](10) NULL,
 CONSTRAINT [PK_stackoverflow_329931_a] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[stackoverflow_329931_b](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [col2] [nchar](10) NULL,
    [col3] [nchar](10) NULL,
    [col4] [nchar](10) NULL,
 CONSTRAINT [PK_stackoverflow_329931_b] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

DECLARE @table1_name AS varchar(255)
DECLARE @table1_prefix AS varchar(255)
DECLARE @table2_name AS varchar(255)
DECLARE @table2_prefix AS varchar(255)
DECLARE @join_condition AS varchar(255)
SET @table1_name = 'stackoverflow_329931_a'
SET @table1_prefix = 'a_'
SET @table2_name = 'stackoverflow_329931_b'
SET @table2_prefix = 'b_'
SET @join_condition = 'a.[id] = b.[id]'

DECLARE @CRLF AS varchar(2)
SET @CRLF = CHAR(13) + CHAR(10)

DECLARE @a_columnlist AS varchar(MAX)
DECLARE @b_columnlist AS varchar(MAX)
DECLARE @sql AS varchar(MAX)

SELECT @a_columnlist = COALESCE(@a_columnlist + @CRLF + ',', '') + 'a.[' + COLUMN_NAME + '] AS [' + @table1_prefix + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @table1_name
ORDER BY ORDINAL_POSITION

SELECT @b_columnlist = COALESCE(@b_columnlist + @CRLF + ',', '') + 'b.[' + COLUMN_NAME + '] AS [' + @table2_prefix + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @table2_name
ORDER BY ORDINAL_POSITION

SET @sql = 'SELECT ' + @a_columnlist + '
,' + @b_columnlist + '
FROM [' + @table1_name + '] AS a
INNER JOIN [' + @table2_name + '] AS b
ON (' + @join_condition + ')'

PRINT @sql
-- EXEC (@sql)
Cade Roux
źródło
to by działało, ale pytanie jest raczej głupie. dlaczego nie wykonać po prostu unii lub sub-zapytania. Dlaczego warto dołączyć i nadal chcieć prefiksy tabel w nazwach kolumn?
D3vtr0n
Cade: dziękuję za informacje, które są interesujące. Niestety generowanie / modyfikowanie bazy danych nie jest w moim przypadku opcją. Devtron: jeśli próbujesz odwzorować informacje pochodzące z zapytania na różne właściwości obiektu, informacje te stają się bardzo przydatne.
foxdonut
1
Czasami nazwy kolumn w różnych tabelach są takie same, ale nie zawierają tych samych wartości. Stąd potrzeba ich prefiksu, aby odróżnić je w widokach lub tabelach pochodnych (które muszą mieć wszystkie unikalne nazwy kolumn).
Cade Roux,
@Frederic, twój kod musi gdzieś mieszkać - to po prostu generuje kod. Ponownie można to zrobić raz podczas programowania lub dynamicznie w czasie wykonywania.
Cade Roux,
1

Są dwa sposoby, dzięki którym mogę to zrobić w sposób wielokrotnego użytku. Jednym z nich jest zmiana nazwy wszystkich kolumn z prefiksem dla tabeli, z której pochodzą. Widziałem to wiele razy, ale naprawdę mi się to nie podoba. Uważam, że jest zbędny, powoduje dużo pisania i zawsze możesz używać aliasów, gdy potrzebujesz zakryć przypadek nazwy kolumny o niejasnym pochodzeniu.

Innym sposobem, który zaleciłbym zrobić w twojej sytuacji, jeśli jesteś zaangażowany w to, jest tworzenie widoków dla każdej tabeli, która będzie aliasami nazw tabel. Następnie łączysz się z tymi widokami, a nie z tabelami. W ten sposób możesz swobodnie używać *, jeśli chcesz, możesz swobodnie korzystać z oryginalnych tabel z oryginalnymi nazwami kolumn, jeśli chcesz, a także ułatwia pisanie kolejnych zapytań, ponieważ już zmieniłeś nazwę w widokach.

Wreszcie nie jestem jasne, dlaczego musisz wiedzieć, z której tabeli pochodzi każda kolumna. Czy to ma znaczenie Najważniejsze są dane, które zawierają. Nie ma znaczenia, czy identyfikator użytkownika pochodzi z tabeli użytkownika, czy z tabeli pytań użytkownika. Ma to oczywiście znaczenie, gdy trzeba go zaktualizować, ale w tym momencie powinieneś już znać swój schemat na tyle dobrze, aby to ustalić.

RedFilter
źródło
„Wreszcie nie jestem jasne, dlaczego musisz wiedzieć, z której tabeli pochodzi każda kolumna. Czy to ma znaczenie?” <- 11 lat później, jednym z przypadków użycia jest skanowanie struktur w Go.
Lee Benson,
1

Lub możesz użyć Red Gate SQL Refactor lub SQL Monit, który rozwija SELECT * w listy kolumn za pomocą kliknięcia przycisku Tab

więc w twoim przypadku, jeśli wpiszesz SELECT * FROM A JOIN B ... Idź na koniec *, przycisk Tab, voila! zobaczysz WYBIERZ A. kolumna 1, A. kolumna 2, ...., B. kolumna 1, B. kolumna 2 Z DOŁĄCZENIA B

Nie jest jednak darmowy

jerryhung
źródło
1

Nie możesz tego zrobić bez aliasingu, po prostu dlatego, jak zamierzasz odwoływać się do pola w klauzuli where, jeśli to pole istnieje w 2 lub 3 tabelach, do których dołączasz? Dla mysql nie będzie jasne, do którego chcesz się odwoływać.

kobejr
źródło
1

Rozwiązałem podobny mój problem, zmieniając nazwy pól w odpowiednich tabelach. Tak, miałem zaszczyt to robić i rozumiem, że każdy może tego nie mieć. Dodałem przedrostek do każdego pola w tabeli reprezentującej nazwę tabeli. Zatem SQL wysłany przez OP pozostałby niezmieniony -

SELECT a.*, b.* FROM TABLE_A a JOIN TABLE_B b USING (some_id);

i nadal dają oczekiwane wyniki - łatwość identyfikacji, do której tabeli należą pola wyjściowe.

Sam
źródło
0

select * zwykle powoduje zły kod, ponieważ nowe kolumny często się dodają lub kolejność kolumn zmienia się dość często w tabelach, co zwykle psuje select * w bardzo subtelny sposób. Zatem wylistowanie kolumn jest właściwym rozwiązaniem.

Jeśli chodzi o sposób wykonania zapytania, nie jestem pewien co do mysql, ale w sqlserver możesz wybrać nazwy kolumn z syscolumns i dynamicznie zbudować klauzulę select.

Kozyarchuk
źródło
Podkreślono, ale w moim kontekście potrzebuję czegoś ogólnego i dynamicznego, więc w rzeczywistości mój kod dostosuje się do nowych kolumn dodawanych / zmienianych / etc. Nie chcę wymieniać kolumn indywidualnie.
foxdonut
5
Wybieranie z syscolumn do dynamicznego budowania instrukcji select to straszny hack i nie poleciłbym tego w produkcji.
Juliet,
0

Jeśli obawiasz się zmian schematu, może Ci się to przydać: 1. Uruchom zapytanie „Tabela DESCRIBE” na wszystkich zaangażowanych tabelach. 2. Użyj zwróconych nazw pól, aby dynamicznie skonstruować ciąg nazw kolumn poprzedzonych wybranym aliasem.

Chris Jacob
źródło
0

Istnieje bezpośrednia odpowiedź na twoje pytanie dla tych, którzy korzystają z MySQL C-API.

Biorąc pod uwagę SQL:

  SELECT a.*, b.*, c.* FROM table_a a JOIN table_b b USING (x) JOIN table_c c USING (y)

Wyniki z „mysql_stmt_result_metadata ()” podają definicję pól z przygotowanego zapytania SQL w strukturze MYSQL_FIELD []. Każde pole zawiera następujące dane:

  char *name;                 /* Name of column (may be the alias) */
  char *org_name;             /* Original column name, if an alias */
  char *table;                /* Table of column if column was a field */
  char *org_table;            /* Org table name, if table was an alias */
  char *db;                   /* Database for table */
  char *catalog;              /* Catalog for table */
  char *def;                  /* Default value (set by mysql_list_fields) */
  unsigned long length;       /* Width of column (create length) */
  unsigned long max_length;   /* Max width for selected set */
  unsigned int name_length;
  unsigned int org_name_length;
  unsigned int table_length;
  unsigned int org_table_length;
  unsigned int db_length;
  unsigned int catalog_length;
  unsigned int def_length;
  unsigned int flags;         /* Div flags */
  unsigned int decimals;      /* Number of decimals in field */
  unsigned int charsetnr;     /* Character set */
  enum enum_field_types type; /* Type of field. See mysql_com.h for types */

Zwróć uwagę na pola: katalog, tabela, nazwa_Org

Teraz wiesz, które pola w twoim SQL należą do którego schematu (aka katalog) i tabeli. To wystarczy, aby ogólnie zidentyfikować każde pole na podstawie kwerendy sql z wieloma tabelami, bez konieczności aliasu.

Rzeczywisty produkt SqlYOG pokazuje wykorzystanie tych dokładnych danych w takim dworku, że są w stanie niezależnie aktualizować każdą tabelę połączenia wielostolikowego, gdy obecne są pola PK.

J Jorgenson
źródło
0

Rozwijając się z tego rozwiązania , podchodziłbym do problemu w następujący sposób:

Najpierw utwórz listę wszystkich ASinstrukcji:

DECLARE @asStatements varchar(8000)

SELECT @asStatements = ISNULL(@asStatements + ', ','') + QUOTENAME(table_name) + '.' + QUOTENAME(column_name) + ' AS ' + '[' + table_name + '.' + column_name + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TABLE_A' OR TABLE_NAME = 'TABLE_B'
ORDER BY ORDINAL_POSITION

Następnie użyj go w zapytaniu:

EXEC('SELECT ' + @asStatements + ' FROM TABLE_A a JOIN TABLE_B b USING (some_id)');

Może to jednak wymagać modyfikacji, ponieważ coś podobnego jest testowane tylko w SQL Server. Ale ten kod nie działa dokładnie w SQL Server, ponieważ USING nie jest obsługiwany.

Proszę o komentarz, jeśli możesz przetestować / poprawić ten kod np. Dla MySQL.

Antonio
źródło
0

Ostatnio natknąłem się na ten problem w NodeJS i Postgres.

Podejście ES6

Nie znam żadnych funkcji RDBMS, które znają tę funkcję, dlatego utworzyłem obiekt zawierający wszystkie moje pola, np .:

const schema = { columns: ['id','another_column','yet_another_column'] }

Zdefiniowano reduktor do łączenia łańcuchów z nazwą tabeli:

const prefix = (table, columns) => columns.reduce((previous, column) => {
  previous.push(table + '.' + column + ' AS ' + table + '_' + column);
  return previous;
}, []);

Zwraca tablicę ciągów. Nazwij to dla każdej tabeli i połącz wyniki:

const columns_joined = [...prefix('tab1',schema.columns), ...prefix('tab2',schema.columns)];

Wyjście końcowej instrukcji SQL:

console.log('SELECT ' + columns_joined.join(',') + ' FROM tab1, tab2 WHERE tab1.id = tab2.id');
Blair
źródło
Nie ma mowy! To trochę hacky zastrzyk SQL i nie działa z wyrażeniami.
ratijas
0

Zaimplementowałem rozwiązanie oparte na odpowiedzi sugerującej użycie fikcyjnych lub wartowniczych kolumn w węźle. Użyłbyś go, generując SQL, taki jak:

select 
    s.*
  , '' as _prefix__creator_
  , u.*
  , '' as _prefix__speaker_
  , p.*
from statements s 
  left join users u on s.creator_user_id = u.user_id
  left join persons p on s.speaker_person_id = p.person_id

A następnie przetworzenie wiersza, który otrzymałeś ze sterownika bazy danych, jak addPrefixes(row).

Implementacja (oparta na fields/ rowszwróconym przez mój sterownik, ale powinna być łatwa do zmiany dla innych sterowników DB):

const PREFIX_INDICATOR = '_prefix__'
const STOP_PREFIX_INDICATOR = '_stop_prefix'

/** Adds a <prefix> to all properties that follow a property with the name: PREFIX_INDICATOR<prefix> */
function addPrefixes(fields, row) {
  let prefix = null
  for (const field of fields) {
    const key = field.name
    if (key.startsWith(PREFIX_INDICATOR)) {
      if (row[key] !== '') {
        throw new Error(`PREFIX_INDICATOR ${PREFIX_INDICATOR} must not appear with a value, but had value: ${row[key]}`)
      }
      prefix = key.substr(PREFIX_INDICATOR.length)
      delete row[key]
    } else if (key === STOP_PREFIX_INDICATOR) {
      if (row[key] !== '') {
        throw new Error(`STOP_PREFIX_INDICATOR ${STOP_PREFIX_INDICATOR} must not appear with a value, but had value: ${row[key]}`)
      }
      prefix = null
      delete row[key]
    } else if (prefix) {
      const prefixedKey = prefix + key
      row[prefixedKey] = row[key]
      delete row[key]
    }
  }
  return row
}

Test:

const {
  addPrefixes,
  PREFIX_INDICATOR,
  STOP_PREFIX_INDICATOR,
} = require('./BaseDao')

describe('addPrefixes', () => {
  test('adds prefixes', () => {
    const fields = [
      {name: 'id'},
      {name: PREFIX_INDICATOR + 'my_prefix_'},
      {name: 'foo'},
      {name: STOP_PREFIX_INDICATOR},
      {name: 'baz'},
    ]
    const row = {
      id: 1,
      [PREFIX_INDICATOR + 'my_prefix_']: '',
      foo: 'bar',
      [STOP_PREFIX_INDICATOR]: '',
      baz: 'spaz'
    }
    const expected = {
      id: 1,
      my_prefix_foo: 'bar',
      baz: 'spaz',
    }
    expect(addPrefixes(fields, row)).toEqual(expected)
  })
})
Carl G.
źródło
0

Używam programu Excel do połączenia procedury. Na przykład najpierw wybieram * i otrzymuję wszystkie kolumny, wklejam je do Excela. Następnie napisz kod, który muszę otoczyć kolumnę. Powiedzmy, że potrzebowałem reklamy prev do kilku kolumn. Chciałbym mieć moje pola w kolumnie i „jak poprzednio” w kolumnie B, a moje pola ponownie w kolumnie c. W kolumnie d miałbym kolumnę.

Następnie użyj konkatanatu w kolumnie e i połącz je razem, pamiętając o spacji. Następnie wytnij i wklej to do kodu SQL. Użyłem również tej metody do tworzenia instrukcji case dla tego samego pola i innych dłuższych kodów, które muszę zrobić dla każdego pola w tabeli z wieloma polami.

Nathan Michael
źródło
0

W postgres używam funkcji json, aby zamiast tego zwracać obiekty json .... następnie, po zapytaniu, dekoduję pola jsonem z przyrostkiem _json.

TO ZNACZY:

select row_to_json(tab1.*),tab1_json, row_to_json(tab2.*) tab2_json 
 from tab1
 join tab2 on tab2.t1id=tab1.id

następnie w PHP (lub w innym języku), przeglądam zwrócone kolumny i json_decode () je, jeśli mają sufiks „_json” (również usuwam sufiks. Na koniec otrzymuję obiekt o nazwie „tab1”, który zawiera wszystkie pola tab1 i inne o nazwie „tab2”, które obejmuje wszystkie pola tab2.

Joe Love
źródło
-1

PHP 7.2 + MySQL / Mariadb

MySQL wyśle ​​Ci wiele pól o tej samej nazwie. Nawet w kliencie terminalowym. Ale jeśli chcesz mieć tablicę asocjacyjną, musisz samodzielnie wykonać klucze.

Dzięki @axelbrz za oryginał. Przeniesiłem go do nowszego php i trochę go wyczyściłem:

function mysqli_rows_with_columns($link, $query) {
    $result = mysqli_query($link, $query);
    if (!$result) {
        return mysqli_error($link);
    }
    $field_count = mysqli_num_fields($result);
    $fields = array();
    for ($i = 0; $i < $field_count; $i++) {
        $field = mysqli_fetch_field_direct($result, $i);
        $fields[] = $field->table . '.' . $field->name; # changed by AS
        #$fields[] = $field->orgtable . '.' . $field->orgname; # actual table/field names
    }
    $rows = array();
    while ($row = mysqli_fetch_row($result)) {
        $new_row = array();
        for ($i = 0; $i < $field_count; $i++) {
            $new_row[$fields[$i]] = $row[$i];
        }
        $rows[] = $new_row;
    }
    mysqli_free_result($result);
    return $rows;
}

$link = mysqli_connect('localhost', 'fixme', 'fixme', 'fixme');
print_r(mysqli_rows_with_columns($link, 'select foo.*, bar.* from foo, bar'));
JasonWoof
źródło