SQL Select Join: Ist es möglich, allen Spalten das Präfix 'Präfix. *' Vorzugeben?

206

Ich frage mich, ob dies in SQL möglich ist. Angenommen, Sie haben zwei Tabellen A und B, und Sie wählen in Tabelle A aus und verbinden sich in Tabelle B:

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

Wenn Tabelle A die Spalten 'a_id', 'name' und 'some_id' enthält und Tabelle B 'b_id', 'name' und 'some_id' enthält, gibt die Abfrage die Spalten 'a_id', 'name', 'some_id' zurück ',' b_id ',' name ',' some_id '. Gibt es eine Möglichkeit, die Spaltennamen von Tabelle B voranzustellen, ohne jede Spalte einzeln aufzulisten? Das Äquivalent dazu:

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);

Aber wie erwähnt, ohne jede Spalte aufzulisten, so etwas wie:

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

Grundsätzlich etwas zu sagen: "Stellen Sie jeder von b. * Zurückgegebenen Spalte 'etwas' voran". Ist das möglich oder habe ich kein Glück?

Vielen Dank im Voraus für Ihre Hilfe!

BEARBEITEN: Ratschläge zur Nichtverwendung von SELECT * usw. sind gültige Ratschläge, aber in meinem Kontext nicht relevant. Halten Sie sich daher bitte an das vorliegende Problem. Ist es möglich, allen ein Präfix (eine in der SQL-Abfrage angegebene Konstante) hinzuzufügen? Spaltennamen einer Tabelle in einem Join?

BEARBEITEN: Mein letztendliches Ziel ist es, ein SELECT * für zwei Tabellen mit einem Join durchzuführen und anhand der Namen der Spalten in meiner Ergebnismenge zu erkennen, welche Spalten aus Tabelle A stammen und welche Spalten stammen aus Tabelle B. Auch hier möchte ich keine Spalten einzeln auflisten müssen, sondern muss in der Lage sein, SELECT * auszuführen.

Fuchsdonut
quelle
Was genau erwarten Sie vom Ergebnis Ihrer Anfrage? Ich bin verwirrt
GregD
GregD: Ich möchte, dass allen Spaltennamen, die aus b. * Kommen, eine von mir angegebene Konstante vorangestellt wird. Anstelle von 'Name' und 'Nummer' möchte ich beispielsweise das Präfix 'special_' angeben und 'special_name' und 'special_number' erhalten. Aber ich möchte dies nicht für jede Spalte einzeln tun.
Foxdonut
6
Wenn ich schnell SELECT mache, um Spalten aus mehreren Tabellen anzuzeigen, wähle ich manchmal 'AAAAA', A. *, 'BBBBB', B. * FROM TableA als JOIN TableB AS B ON A.ID = B.ID, damit ich Haben Sie mindestens eine Tabellenkennung beim Scannen entlang der Zeilen
Kristen
Mögliches Duplikat: stackoverflow.com/questions/2595068/…
Andrioid

Antworten:

35

Ich sehe hier zwei mögliche Situationen. Zunächst möchten Sie wissen, ob es dafür einen SQL-Standard gibt, den Sie im Allgemeinen unabhängig von der Datenbank verwenden können. Nein, da ist kein. Zweitens möchten Sie wissen, was ein bestimmtes DBMS-Produkt betrifft. Dann müssen Sie es identifizieren. Aber ich stelle mir vor, die wahrscheinlichste Antwort ist, dass Sie so etwas wie "a.id, b.id" zurückbekommen, da Sie auf diese Weise die Spalten in Ihrem SQL-Ausdruck identifizieren müssten. Der einfachste Weg, um herauszufinden, was die Standardeinstellung ist, besteht darin, eine solche Abfrage zu senden und zu sehen, was Sie zurückerhalten. Wenn Sie angeben möchten, welches Präfix vor dem Punkt steht, können Sie beispielsweise "SELECT * FROM a AS my_alias" verwenden.

dkretz
quelle
11
Ich bin mir nicht sicher, wie dies Ihre Frage beantwortet. Ich verwende MS SQL Server und füge einen Alias ​​hinzu, nachdem der Tabellenname den Alias ​​nicht an die Spaltennamen in der Ergebnismenge anhängt.
Paiego
74

Die Antwort auf Ihre Frage scheint Nein zu sein. Sie können jedoch auch eine Dummy-Spalte zuweisen, um jede neue Tabelle zu trennen. Dies funktioniert besonders gut, wenn Sie eine Ergebnismenge für eine Liste von Spalten in einer Skriptsprache wie Python oder PHP durchlaufen.

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

Mir ist klar, dass dies Ihre Frage nicht genau beantwortet, aber wenn Sie ein Codierer sind, ist dies eine großartige Möglichkeit, Tabellen mit doppelten Spaltennamen zu trennen. Hoffe das hilft jemandem.

Wayne Bryan
quelle
24

Ich verstehe vollkommen, warum dies notwendig ist - zumindest für mich ist es beim Rapid Prototyping praktisch, wenn viele Tabellen verbunden werden müssen, einschließlich vieler innerer Verknüpfungen. Sobald ein Spaltenname in einem zweiten Platzhalter für "jointable. *" -Feld identisch ist, werden die Feldwerte der Haupttabelle mit den Werten für jointable überschrieben. Fehleranfällig, frustrierend und eine Verletzung von DRY, wenn die Tabellenfelder immer wieder manuell mit Aliasnamen angegeben werden müssen ...

Hier ist eine PHP-Funktion (Wordpress), um dies durch Codegenerierung zu erreichen, zusammen mit einem Beispiel für deren Verwendung. In diesem Beispiel wird es verwendet, um schnell eine benutzerdefinierte Abfrage zu generieren, die die Felder eines verwandten WordPress-Beitrags bereitstellt, auf den über ein erweitertes Feld für benutzerdefinierte Felder verwiesen wurde .

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>";
}

Die Ausgabe:

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
quelle
13

Die einzige mir bekannte Datenbank, die dies tut, ist SQLite, abhängig von den Einstellungen, die Sie mit PRAGMA full_column_namesund konfigurieren PRAGMA short_column_names. Siehe http://www.sqlite.org/pragma.html

Ansonsten kann ich nur empfehlen, Spalten in einer Ergebnismenge nach Ordnungsposition und nicht nach Spaltennamen abzurufen, wenn Sie zu viel Mühe haben, die Namen der Spalten in Ihre Abfrage einzugeben.

Dies ist ein gutes Beispiel dafür, warum es eine schlechte Praxis ist, sie zu verwenden,SELECT * da Sie schließlich ohnehin alle Spaltennamen eingeben müssen.

Ich verstehe die Notwendigkeit, Spalten zu unterstützen, deren Name oder Position sich ändern kann, aber die Verwendung von Platzhaltern macht dies schwieriger und nicht einfacher.

Bill Karwin
quelle
2
Beachten Sie, dass beide full_column_namesund in SQLite veraltetshort_column_names sind .
Isanae
6

Ich bin in der Art des gleichen Bootes wie OP - ich habe Dutzende von Feldern aus 3 verschiedenen Tabellen, denen ich beitrete, von denen einige den gleichen Namen haben (dh ID, Name usw.). Ich möchte nicht jedes Feld auflisten, daher bestand meine Lösung darin, die Felder mit einem gemeinsamen Namen zu aliasen und select * für diejenigen zu verwenden, die einen eindeutigen Namen haben.

Zum Beispiel :

Tabelle a: ID, Name, Feld1, Feld2 ...

Tabelle b: ID, Name, Feld3, Feld4 ...

Wählen Sie a.id als aID, a.name als aName, a. *, b.id als bID, b.name als bName, b. * .....

Beim Zugriff auf die Ergebnisse habe ich die Aliasnamen für diese Felder und ignoriere die "ursprünglichen" Namen.

Vielleicht nicht die beste Lösung, aber es funktioniert für mich ... ich benutze MySQL


quelle
5

Verschiedene Datenbankprodukte geben Ihnen unterschiedliche Antworten. Aber Sie bereiten sich auf Verletzungen vor, wenn Sie dies sehr weit tragen. Sie sind weitaus besser dran, die gewünschten Spalten auszuwählen und ihnen Ihre eigenen Aliase zu geben, damit die Identität jeder Spalte kristallklar ist und Sie sie in den Ergebnissen unterscheiden können.

dkretz
quelle
1
Punkt genommen, aber mein Ziel hier ist etwas sehr Allgemeines, also ist es kein Problem, nicht explizit zu sein. In der Tat wäre es ein Problem , spezifisch sein zu müssen.
Foxdonut
Siehe weitere Einreichung unten. Kann dot.notation verwenden, was wahrscheinlich die Standardeinstellung ist?
dkretz
Es ist wichtig für die Lesbarkeit. Ich hatte gehofft, dies jetzt zu tun, weil ich einen lniked CTE-Prozess habe. Ex. CTE_A -> CTE_B -> CTE_C -> CTE_D -> Auswählen / Einfügen Die gewünschten Spalten müssen erst angegeben werden, wenn die endgültige select-Anweisung und die Leistung keine Rolle spielen.
ThomasRones
5

Diese Frage ist in der Praxis sehr nützlich. Es ist nur erforderlich, alle expliziten Spalten in der Softwareprogrammierung aufzulisten, wobei Sie besonders darauf achten, mit allen Bedingungen umzugehen.

Stellen Sie sich vor, wir müssen beim Debuggen oder beim Versuch, DBMS als tägliches Office-Tool zu verwenden, anstelle einer veränderbaren Implementierung der abstrakten zugrunde liegenden Infrastruktur eines bestimmten Programmierers viele SQLs codieren. Das Szenario ist überall zu finden, z. B. bei der Datenbankkonvertierung, Migration, Verwaltung usw. Die meisten dieser SQLs werden nur einmal ausgeführt und nie wieder verwendet. Geben Sie an, dass jeder Spaltenname nur Zeitverschwendung ist. Und vergessen Sie nicht, dass die Erfindung von SQL nicht nur für Programmierer gedacht ist.

Normalerweise erstelle ich eine Dienstprogrammansicht mit vorangestellten Spaltennamen. Hier ist die Funktion in pl / pgsql. Es ist nicht einfach, aber Sie können sie in andere Prozedursprachen konvertieren.

-- 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;

Beispiele:

-- 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
quelle
3

Ich verstehe Ihr Problem mit doppelten Feldnamen vollkommen.

Ich brauchte das auch, bis ich meine eigene Funktion codierte, um es zu lösen. Wenn Sie PHP verwenden, können Sie es verwenden oder Ihre in der Sprache codieren, für die Sie sie verwenden, wenn Sie über die folgenden Funktionen verfügen.

Der Trick dabei ist, dass mysql_field_table()der Tabellenname und mysql_field_name()das Feld für jede Zeile im Ergebnis zurückgegeben werden, wenn es mit kommtmysql_num_fields() sodass Sie sie in einem neuen Array mischen können.

Dies stellt alle Spalten voran;)

Grüße,

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
quelle
2

Hierfür gibt es keinen SQL-Standard.

Mit der Codegenerierung (entweder bei Bedarf beim Erstellen oder Ändern der Tabellen oder zur Laufzeit) können Sie dies jedoch ganz einfach tun:

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
quelle
Das würde funktionieren, aber die Frage ist ziemlich dumm. Warum nicht einfach eine Vereinigung oder Unterabfrage durchführen? Warum sollten Sie beitreten und weiterhin Tabellenpräfixe in den Spaltennamen wünschen?
D3vtr0n
Cade: Danke für die Info, das ist interessant. Leider ist das Generieren / Ändern der Datenbank in meinem Fall keine Option. Devtron: Wenn Sie versuchen, die Informationen, die von einer Abfrage zurückkommen, verschiedenen Eigenschaften eines Objekts zuzuordnen, werden diese Informationen sehr nützlich.
Foxdonut
1
Manchmal sind Spaltennamen in verschiedenen Tabellen gleich, enthalten jedoch nicht dieselben Werte. Daher müssen sie vorangestellt werden, um sie in Ansichten oder abgeleiteten Tabellen zu unterscheiden (die alle eindeutigen Spaltennamen haben müssen).
Cade Roux
@Frederic, dein Code muss irgendwo leben - dies generiert nur den Code. Dies kann wiederum einmal während der Entwicklung oder dynamisch zur Laufzeit erfolgen.
Cade Roux
1

Ich kann mir zwei Möglichkeiten vorstellen, um dies auf wiederverwendbare Weise zu erreichen. Eine besteht darin, alle Ihre Spalten mit einem Präfix für die Tabelle umzubenennen, aus der sie stammen. Ich habe das schon oft gesehen, aber ich mag es wirklich nicht. Ich finde, dass es redundant ist, viel Tipparbeit verursacht und Sie immer Aliase verwenden können, wenn Sie den Fall eines Spaltennamens mit unklarem Ursprung abdecken müssen.

Die andere Möglichkeit, die ich Ihnen in Ihrer Situation empfehlen würde, wenn Sie dies durchschauen möchten, besteht darin, Ansichten für jede Tabelle zu erstellen, die den Alias ​​der Tabellennamen enthält. Dann verbinden Sie sich mit diesen Ansichten und nicht mit den Tabellen. Auf diese Weise können Sie * verwenden, wenn Sie möchten, und die ursprünglichen Tabellen mit den ursprünglichen Spaltennamen verwenden, wenn Sie möchten. Außerdem können Sie nachfolgende Abfragen einfacher schreiben, da Sie die Umbenennungsarbeiten in den Ansichten bereits durchgeführt haben.

Schließlich ist mir nicht klar, warum Sie wissen müssen, aus welcher Tabelle die einzelnen Spalten stammen. Ist das wichtig? Letztendlich kommt es auf die Daten an, die sie enthalten. Ob UserID aus der User-Tabelle oder der UserQuestion-Tabelle stammt, spielt keine Rolle. Es ist natürlich wichtig, wann Sie es aktualisieren müssen, aber zu diesem Zeitpunkt sollten Sie Ihr Schema bereits gut genug kennen, um dies festzustellen.

RedFilter
quelle
"Schließlich ist mir nicht klar, warum Sie wissen müssen, aus welcher Tabelle jede der Spalten stammt. Ist das wichtig?" <- 11 Jahre später ist ein Anwendungsfall das Struktur-Scannen in Go.
Lee Benson
1

Sie können auch Red Gate SQL Refactor oder SQL Prompt verwenden, mit denen Sie SELECT * mit einem Klick auf die Tabulatortaste in Spaltenlisten erweitern können

Wenn Sie also in Ihrem Fall SELECT * FROM A JOIN B eingeben ... Gehen Sie zum Ende von *, Tab-Taste, voila! Sie sehen SELECT A.column1, A.column2, ...., B.column1, B.column2 FROM A JOIN B.

Es ist jedoch nicht kostenlos

Jerryhung
quelle
1

Kann dies nicht ohne Aliasing tun, einfach weil, wie werden Sie auf ein Feld in der where-Klausel verweisen, wenn dieses Feld in den 2 oder 3 Tabellen vorhanden ist, denen Sie beitreten? Es wird für MySQL unklar sein, auf welche Sie sich beziehen möchten.

kobejr
quelle
1

Ich habe ein ähnliches Problem gelöst, indem ich die Felder in den beteiligten Tabellen umbenannt habe. Ja, ich hatte das Privileg, dies zu tun und zu verstehen, dass es möglicherweise nicht jeder hat. Ich habe jedem Feld in einer Tabelle, die den Tabellennamen darstellt, ein Präfix hinzugefügt. Somit würde die von OP gepostete SQL unverändert bleiben -

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

und trotzdem die erwarteten Ergebnisse liefern - einfache Identifizierung, zu welcher Tabelle die Ausgabefelder gehören.

Sam
quelle
0

select * führt normalerweise zu schlechtem Code, da neue Spalten häufig hinzugefügt werden oder die Reihenfolge der Spalten in Tabellen häufig geändert wird, wodurch select * normalerweise auf sehr subtile Weise unterbrochen wird. Das Auflisten von Spalten ist also die richtige Lösung.

Sie sind sich nicht sicher über MySQL, aber in SQL Server können Sie Spaltennamen aus Syscolumns auswählen und die select-Klausel dynamisch erstellen.

Kozyarchuk
quelle
Punkt genommen, aber in meinem Kontext brauche ich etwas Allgemeines und Dynamisches, so dass sich mein Code tatsächlich an neue Spalten anpasst, die hinzugefügt / neu angeordnet / etc. Ich möchte keine Spalten einzeln auflisten müssen.
Foxdonut
5
Die Auswahl aus syscolumns zum dynamischen Erstellen einer select-Anweisung ist ein schrecklicher Hack, und ich würde ihn in der Produktion nicht empfehlen.
Julia
0

Wenn Sie Bedenken hinsichtlich Schemaänderungen haben, funktioniert dies möglicherweise für Sie: 1. Führen Sie für alle beteiligten Tabellen eine Abfrage 'DESCRIBE table' aus. 2. Verwenden Sie die zurückgegebenen Feldnamen, um dynamisch eine Zeichenfolge von Spaltennamen zu erstellen, denen der ausgewählte Alias ​​vorangestellt ist.

Chris Jacob
quelle
0

Für diejenigen, die die MySQL C-API verwenden, gibt es eine direkte Antwort auf Ihre Frage.

Angesichts der SQL:

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

Die Ergebnisse von 'mysql_stmt_result_metadata ()' geben die Definition Ihrer Felder aus Ihrer vorbereiteten SQL-Abfrage in die Struktur MYSQL_FIELD []. Jedes Feld enthält die folgenden Daten:

  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 */

Beachten Sie die Felder: Katalog, Tabelle, Organisationsname

Sie wissen jetzt, welche Felder in Ihrem SQL zu welchem ​​Schema (auch bekannt als Katalog) und Tabelle gehören. Dies reicht aus, um jedes Feld generisch aus einer SQL-Abfrage mit mehreren Tabellen zu identifizieren, ohne dass ein Alias ​​erstellt werden muss.

Es wird gezeigt, dass ein tatsächliches Produkt, SqlYOG, genau diese Daten in einem solchen Manor verwendet, dass es in der Lage ist, jede Tabelle eines Joins mit mehreren Tabellen unabhängig zu aktualisieren, wenn die PK-Felder vorhanden sind.

J Jorgenson
quelle
0

Aus dieser Lösung heraus würde ich das Problem folgendermaßen angehen:

Erstellen Sie zunächst eine Liste aller ASAnweisungen:

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

Verwenden Sie es dann in Ihrer Abfrage:

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

Dies muss jedoch möglicherweise geändert werden, da etwas Ähnliches nur in SQL Server getestet wird. Dieser Code funktioniert jedoch nicht genau in SQL Server, da USING nicht unterstützt wird.

Bitte kommentieren Sie, ob Sie diesen Code zB für MySQL testen / korrigieren können.

Antonio
quelle
0

Kürzlich ist dieses Problem in NodeJS und Postgres aufgetreten.

ES6-Ansatz

Da mir keine RDBMS-Funktionen bekannt sind, die diese Funktionalität bieten, habe ich ein Objekt erstellt, das alle meine Felder enthält, z.

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

Definierte einen Reduzierer, um die Zeichenfolgen zusammen mit einem Tabellennamen zu verketten:

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

Dies gibt ein Array von Zeichenfolgen zurück. Nennen Sie es für jede Tabelle und kombinieren Sie die Ergebnisse:

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

Geben Sie die endgültige SQL-Anweisung aus:

console.log('SELECT ' + columns_joined.join(',') + ' FROM tab1, tab2 WHERE tab1.id = tab2.id');
Blair
quelle
Auf keinen Fall! Das ist eine hackige SQL-Injection und funktioniert nicht mit Ausdrücken.
Ratijas
0

Ich habe eine Lösung implementiert, die auf der Antwort basiert, die die Verwendung von Dummy- oder Sentinel-Spalten im Knoten vorschlägt . Sie würden es verwenden, indem Sie SQL wie folgt generieren:

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

Und dann die Zeile nachbearbeiten, die Sie von Ihrem Datenbanktreiber erhalten, wie addPrefixes(row).

Die Umsetzung (bezogen auf das fields/ rowszurückgekehrt von meinem Fahrer, sondern sollte einfach sein , für andere DB - Treiber zu ändern):

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
}

Prüfung:

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.
quelle
0

Ich verwende Excel, um die Prozedur zu verketten. Zum Beispiel wähle ich zuerst * aus und erhalte alle Spalten, füge sie in Excel ein. Schreiben Sie dann den Code auf, den ich zum Umgeben der Spalte benötige. Angenommen, ich musste eine Reihe von Spalten anzeigen. Ich hätte meine Felder in der Spalte a und "as prev_" in Spalte B und meine Felder wieder in Spalte c. In Spalte d hätte ich eine Spalte.

Verwenden Sie dann concatanate in Spalte e und führen Sie sie zusammen, wobei Sie darauf achten, Leerzeichen einzuschließen. Dann schneiden Sie dies aus und fügen Sie es in Ihren SQL-Code ein. Ich habe diese Methode auch verwendet, um case-Anweisungen für dasselbe Feld und andere längere Codes zu erstellen, die ich für jedes Feld in einer Tabelle mit mehreren hundert Feldern ausführen muss.

Nathan Michael
quelle
0

In postgres verwende ich die json-Funktionen, um stattdessen json-Objekte zurückzugeben. Nach der Abfrage codiere ich die Felder mit dem Suffix _json.

IE:

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

Dann durchlaufe ich in PHP (oder einer anderen Sprache) die zurückgegebenen Spalten und json_decode (), wenn sie das Suffix "_json" haben (wobei auch das Suffix entfernt wird. Am Ende erhalte ich ein Objekt namens "tab1", das alle enthält tab1-Felder und ein anderes mit dem Namen "tab2", das alle tab2-Felder enthält.

Joe Love
quelle
-1

PHP 7.2 + MySQL / Mariadb

MySQL sendet Ihnen mehrere Felder mit demselben Namen. Auch im Terminal-Client. Wenn Sie jedoch ein assoziatives Array möchten, müssen Sie die Schlüssel selbst erstellen.

Danke an @axelbrz für das Original. Ich habe es auf neueres PHP portiert und ein wenig aufgeräumt:

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
quelle