69

私はかなり恐ろしいレガシーデータベース/コードベースを分析しており、クエリを結合に結合することでサーバーの負荷を軽減しようとしています(通常、100万を超える個別のクエリを呼び出す電子メールアラートcronジョブを含む)。

SELECT * FROM 
class_alerts_holding ah 
INNER JOIN class_listings l ON l.id = ah.lid 
INNER JOIN class_users u ON u.id = ah.uid
LEFT JOIN class_prodimages pi ON pi.pid = ah.lid

これは120列を吐き出します...

aid | id | lid | uid | oid | catName | searchtext | alertfreq | listType | id | owner | title | section | shortDescription | description | featured | price | display | hitcount | dateadded | expiration | url | notified | searchcount | repliedcount | pBold | pHighlighted | notes | ...

新しいクエリを作成する方法の分析を支援するために、結果の列にJOINで取得したテーブルのプレフィックスを付けることができれば素晴らしいと思います。

class_alerts_holding.aid | class_alerts_holding.id | class_listings.lid | ...

これを達成する方法はありますか?

4

10 に答える 10

46

あなたは出来る

select ah.*, l.*, u.*, pi.* from ...

その場合、列は少なくともテーブル順に返されます。

2セットの列ごとを区別しやすくするために、次のような「区切り文字」列を追加することもできます。

select ah.*, ':', l.*, ':', u.*, ':', pi.* from ...

(明示的なエイリアスを不要として削除するように編集しました。コメントを参照してください。)

于 2012-10-31T07:51:11.773 に答える
35

クエリのフィールドに名前を付けて、エイリアスを付けることができます。

SELECT     ah.whateverfield1 AS 'ah_field1',
           ah.whateverfield2 AS 'ah_field2',
           l.whateverfield3 AS 'l.field3',
           [....]
FROM       class_alerts_holding ah 
INNER JOIN class_listings l ON l.id = ah.lid 
INNER JOIN class_users u ON u.id = ah.uid
LEFT JOIN  class_prodimages pi ON pi.pid = ah.lid

フィールドがたくさんある場合は手動で設定するのは少し手間がかかりますが、このクエリを使用するとこれを簡略化できます...

SHOW FULL FIELDS FROM your_table_name;

...そして優れたテキストエディタとコピー&ペースト。

于 2012-10-31T07:48:47.990 に答える
15

結合内のテーブル名でフィールド名のプレフィックスやポストフィックスを行うこのような機能は、ANSISQL標準に含める必要があると確信しています。現在、2019年には、それを行うためのエレガントなクロスプラットフォームの方法はまだありません。残っているのは、エイリアスを使用した見栄えが悪く、エラーが発生しやすい手動ハッキング、または動的SQLを含むプラットフォーム固有のソリューションです。'dot-star'(。*)で示されるフィールドにカスタムプレフィックスまたは/およびポストフィックスを指定する機能があると、誰もが本当に恩恵を受けるでしょう。このような機能を追加した後のサンプル選択は次のようになります。

select a.* use prefix,b.* use postfix '_b' from table_a a inner join table_b b on a.id=b.id

ご覧のとおり、デフォルトでは、プレフィックスまたはポストフィックスはテーブル名(またはエイリアス名)と等しく、任意の文字列リテラルでオーバーライドできます。

また、標準に追加されるのは、すべてのフィールドを選択するためのショートカットである「スター付き」(*)出力から特定のフィールドを除外する機能です。ネットワークデータ転送や簡潔さを減らすために含めたくないファイルをリストするために、キーワードを 除いて追加します。例:

select * except large_binary_data_field,another_notneeded_field,etc from my_table

このような機能により、スターと不要ないくつかのフィールドのみを指定するのではなく、必要なフィールドの完全な(そして潜在的に大きな)リストを明示的に指定する必要がなくなります。

したがって、この投稿を読んでANSI SQL標準インフルエンサーに連絡できる人は誰でも、何をすべきかを知っています)

PS さらに別の醜いですが、少なくとも自動化された汎用の動的SQLラッパー

psycopgを使用するPython支持者のために、ここに私が使用する便利なサブがあります(SQLインジェクションの可能性があるため、厳密には内部的に)

def get_table_fields(table,alias,prefix='',suffix='',excluding=''):
    if type(excluding)==str: excluding=excluding.split(',')
    cur.execute('select * from '+table+' where 0=1');cur.fetchall()
    if not (cur.description is None):        
        return ','.join([alias+'.'+col.name+' '+prefix+col.name+suffix for col in cur.description if not (col.name in excluding)])

そして、3つのテーブルを結合していて、データセットテーブルから大きなデータフィールドをフェッチしないようにしたい呼び出しコード:

sql="""select %s,%s,%s from tasks t,features_sets f,datasets d 
        where 
                t.is_active=true and f.is_active=true 
                and f.task=t.id and t.train_dataset=d.id 
    """ % (
        get_table_fields('tasks','t',prefix='ts_'),
        get_table_fields('features_sets','f',prefix='fs_'),
        get_table_fields('datasets','d',prefix='ds_',excluding='data')
    )

それは私のために強力に展開されます

select t.id ts_id,t.project ts_project,t.name ts_name,***,
    fs_id,f.task fs_task,f.name fs_name,f.description fs_description,***,
    d.id ds_id,d.project ds_project,d.name ds_name,***
from tasks t,features_sets f,datasets d 
    where 
        t.is_active=true and f.is_active=true 
        and f.task=t.id and t.train_dataset=d.id 

ここで、***は他の多くの有用なフィールドを意味し、それらのいくつかは複数のテーブルに共通です(したがって、接頭辞が必要です)。curは明らかにpsycopgカーソルであり、0 = 1条件は、実際のデータなしでフィールド名のみを取得することを目的としています。

于 2019-09-07T10:43:15.653 に答える
12

列に動的に名前を付ける方法は、information_schemaを参照するプリペアドステートメントを生成することです。これにより、探していた結果が得られます。

SET @sql = NULL;
SELECT CONCAT(
   'SELECT ',GROUP_CONCAT(c.TABLE_NAME,'.',c.COLUMN_NAME,' AS `',c.TABLE_NAME,'.',c.COLUMN_NAME,'`'),'
    FROM class_alerts_holding 
    INNER JOIN class_listings ON class_listings.id = class_alerts_holding.lid 
    INNER JOIN class_users ON class_users.id = class_alerts_holding.uid
    LEFT JOIN class_prodimages ON class_prodimages.pid = class_alerts_holding.lid'
)
INTO @sql
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_NAME IN ('class_alerts_holding','class_listings',
                       'class_users','class_prodimages');    
PREPARE sql_statement FROM @sql;
EXECUTE sql_statement;

GROUP_CONCAT()関数のデフォルトの制限は1024文字であるため、テーブルの列数によっては、プリペアドステートメントを生成するためにこの制限を上げる必要がある場合があります。

SET SESSION group_concat_max_len = 1000000;

このコマンドは、必要に応じてグループ連結制限を引き上げます。-

于 2013-06-06T15:35:40.793 に答える
8

2020年の時点では、これはまだサポートされていないため、クエリのフィールドセットを作成することになりました。

しかし、怠惰なプログラマーである私は、クエリ内のすべてのテーブルに対してこれをすべて手動で入力したくなかったことは明らかです。そこで、selectステートメントを作成するためのクエリを作成しました。

SELECT
    CONCAT(table_name, ".", column_name, " AS ", CHAR(34), table_name, ".", column_name, CHAR(34)) field_names
FROM
    information_schema.columns
WHERE
    table_schema = "my_database"
    AND table_name IN(
        "table_1",
        "table_2"
    );

これは次のようなものを出力します:

| field_names                        |
|------------------------------------|
| table_1.id AS "table_1.id"         |
| table_1.name AS "table_1.name"     |
| table_2.id AS "table_2.id"         |
| table_2.number AS "table_2.number" |

SELECTその後、それをステートメントに簡単にコピーできます。

于 2020-03-24T16:39:03.923 に答える
3

この質問で、クエリで使用する列名を作成するためのMySQL concat()が役立つものを見つけましたか?。これが解決策のひとつになると思います。

于 2012-10-31T08:15:37.603 に答える
3

koljaTMとAndriyMによって提案されたソリューションに基づいて、おそらくさらに良いソリューションは、次のようにクエリを作成することです。

select
  '--TABLE_AAA:--', TABLE_AAA.*,
  '--TABLE_BBB:--', TABLE_BBB.*,
  '--TABLE_CCC:--', TABLE_CCC.*,
  '--TABLE_DDD:--', TABLE_DDD.*
from ...

残念ながら、1つ(または複数)のテーブルに画面幅に収まらないほど多くの列名が含まれている場合、これではまだ十分ではありません。(したがって、画面には20列が表示されますが、それらが由来するテーブルの名前は画面に表示されない場合があります。)

SQLが列名の前にテーブル名を自動的に付ける方法を提供していれば、それでもなお良かったでしょう...

于 2014-03-26T10:49:42.240 に答える
0

@ alden-w、異なるスキーマの同じテーブル名を混同しない場所にTABLE_SCHEMA条件を追加できます

WHERE c.TABLE_SCHEMA='YOUR_SCHEMA_NAME' AND c.TABLE_NAME IN (....)
于 2017-09-15T10:03:19.917 に答える
0
CREATE OR REPLACE FUNCTION getAlias (mytable text, my_alias text, my_prefix text)
RETURNS SETOF TEXT AS $$
   SELECT my_alias || column_name || ' as ' || my_prefix
   FROM information_schema.COLUMNS
   WHERE TABLE_NAME = mytable;
$$ LANGUAGE SQL

--dbに関数を書くことができます。この関数はSQLの標準である必要があります。

于 2021-12-07T06:11:46.603 に答える
-1

テーブル定義に従って、動的SQLを試して外出先でクエリを作成することができます。

declare @col varchar(max)
set @col = Select stuff( 
          (select ', ' + column_name + '.' + table_name 
           from information_schema.columns 
           where table_name in ( 'table1', 'table2' ...) for xml 
           path('')),1,1,'')

declare @query nvarchar(max) = '
select ' + @col + ' 
from table1 
inner join table2 on table1.id = table2.id '

exec sp_executesql @query

于 2019-08-31T08:06:51.137 に答える