我正在分析一个相当可怕的遗留数据库/代码库,尝试通过将查询组合到连接中来减少服务器负载(包括通常调用超过一百万个单独查询的电子邮件警报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)
...还有一个好的文本编辑器和复制粘贴.
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)
(编辑为删除显式别名,请参阅注释.)
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限制. -
我最终只是为查询构建了字段集,截至 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语句中。
| 归档时间: |
|
| 查看次数: |
44551 次 |
| 最近记录: |