在连接中,如何使用它来自的表为所有列名添加前缀

Jar*_*ith 39 mysql sql

我正在分析一个相当可怕的遗留数据库/代码库,尝试通过将查询组合到连接中来减少服务器负载(包括通常调用超过一百万个单独查询的电子邮件警报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
Run Code Online (Sandbox Code Playgroud)

吐出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 | ...
Run Code Online (Sandbox Code Playgroud)

为了帮助我分析如何构造新查询,如果我可以在结果中使用来自JOIN的表格作为结果中的列前缀,那将是非常棒的,例如

class_alerts_holding.aid | class_alerts_holding.id | class_listings.lid | ...
Run Code Online (Sandbox Code Playgroud)

有没有办法实现这个目标?

Bjo*_*ern 34

您可以在查询中命名字段并为其指定别名:

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
Run Code Online (Sandbox Code Playgroud)

如果你有那么多字段,手动设置有点工作,但你可以用这个查询简化这个...

SHOW FULL FIELDS FROM your_table_name;
Run Code Online (Sandbox Code Playgroud)

...还有一个好的文本编辑器和复制粘贴.

  • 所以没有办法只是去表.*作为表,并将表中的所有列作为table.columnName返回? (12认同)

kol*_*aTM 29

你可以

select ah.*, l.*, u.*, pi.* from ...
Run Code Online (Sandbox Code Playgroud)

那么列将至少按表的顺序返回.

为了更好地区分每两组列,您还可以添加"delimiter"列,如下所示:

select ah.*, ':', l.*, ':', u.*, ':', pi.* from ...
Run Code Online (Sandbox Code Playgroud)

(编辑为删除显式别名,请参阅注释.)

  • 具有相同名称(例如 id、name、description)的列消失了! (5认同)

Ana*_*eev 11

我相信这样的特性在连接中使用表名前缀和/或后缀字段名称应该包含在ANSI SQL STANDARD 中。目前,在 2019 年,仍然没有优雅的跨平台方式来做到这一点,剩下的就是使用别名的丑陋且容易出错的手动黑客攻击,或者涉及动态 sql 的特定平台解决方案。每个人都将从能够为由“点星”(.*) 表示的字段指定自定义前缀或/和后缀的能力中受益。添加此类功能后的示例选择将是:

select a.* use prefix,b.* use postfix '_b' from table_a a inner join table_b b on a.id=b.id
Run Code Online (Sandbox Code Playgroud)

如您所见,默认情况下前缀或后缀等于表名(或别名),并且可以用任何所需的字符串文字覆盖。

此外,渴望添加到标准中的是能够从“带星号”(*) 输出中排除某些字段,这是选择所有字段的快捷方式。由于减少网络数据传输或/和简洁的原因,我将添加except关键字以列出我不想包含的字段,例如:

select * except large_binary_data_field,another_notneeded_field,etc from my_table
Run Code Online (Sandbox Code Playgroud)

这样的特性将允许避免显式指定所需字段的完整(并且可能很大)列表的必要性,而不是仅指定星号和一些不需要的字段。

因此,请阅读这篇文章并能够联系 ANSI SQL 标准影响者的人,您知道该怎么做)

PS 又一个丑陋的,但至少是自动化和通用的动态 sql 包装器

对于使用 psycopg 的 Python 拥护者,这里是我使用的方便的 sub(严格来说是在内部,因为它很容易被 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)])
Run Code Online (Sandbox Code Playgroud)

以及调用代码,我在其中加入 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')
    )
Run Code Online (Sandbox Code Playgroud)

为我展开变得强大

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 
Run Code Online (Sandbox Code Playgroud)

其中 *** 表示大量其他有用的字段,其中一些字段对于多个表是常见的(因此需要添加前缀)。cur显然是 psycopg 游标,并且 0=1 条件旨在仅检索没有实际数据的字段名称。


Ald*_* W. 10

动态命名列的方法是生成引用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;
Run Code Online (Sandbox Code Playgroud)

GROUP_CONCAT()函数的默认限制为1024个字符,因此根据表中的列数,您可能需要提高此限制才能生成预准备语句.

SET SESSION group_concat_max_len = 1000000;
Run Code Online (Sandbox Code Playgroud)

如果需要,此命令将提高组concat限制. -


Oth*_*hyn 7

我最终只是为查询构建了字段集,截至 2020 年,这仍然不受支持。

但是,作为一个懒惰的程序员,我显然不想为查询中的所有表手动键入所有内容。所以我写了一个查询来构建选择语句:

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"
    );
Run Code Online (Sandbox Code Playgroud)

这将输出如下内容:

| 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" |
Run Code Online (Sandbox Code Playgroud)

然后可以轻松地将其复制到您的SELECT语句中。

  • 如果你想更懒,你可以这样做 `GROUP_CONCAT(CONCAT(table_name, ".", column_name, " AS \`", table_name, ".", column_name, "\`") SEPARATOR ", ")` 所以仅返回 1 个结果,并且它们已用逗号分隔。 (3认同)