SQLselect连接:是否可以将所有列作为“前缀。*”作为前缀?
我想知道这是否可能在SQL中。 假设你有两个表A和B,你在表A上做了一个select,然后在表B上join:
SELECT a.*, b.* FROM TABLE_A a JOIN TABLE_B b USING (some_id);
如果表A有'a_id','name'和'some_id'列,而B表有'b_id','name'和'some_id',查询将返回列'a_id','name','some_id ','b_id','名称','some_id'。 有没有办法在表B的列名前面加上前缀,而不是单独列出每一列? 这相当于:
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);
但是,如前所述,没有列出每一列,所以如下所示:
SELECT a.*, b.* as 'b.*' FROM TABLE_A a JOIN TABLE_B b USING (some_id);
基本上可以这么说,“用b。*和'something'返回的每一列前缀”。 这是可能的还是我运气不好?
在此先感谢您的帮助!
编辑:关于不使用SELECT *等的build议是有效的build议,但在我的上下文中不相关,所以请坚持手头的问题 – 是否有可能添加一个前缀(SQL查询中指定一个常量)到所有连接中的表的列名?
编辑:我的最终目标是能够在一个连接的两个表上做一个SELECT *,并能够从我在结果集中得到的列的名称中知道哪些列来自表A,哪些列来自从表B.再次,我不想单独列出列,我需要能够做一个SELECT *。
我在这里看到两种可能的情况。 首先,你想知道是否有这样的SQL标准,你可以在一般情况下使用,不pipe数据库如何。 不,那里没有。 其次,你想知道一个特定的dbms产品。 那么你需要确定它。 但我想最可能的答案是,你会得到像“a.id,b.id”这样的事情,因为这是你需要识别SQLexpression式中的列。 找出默认的最简单方法就是提交这样一个查询,看看你回来了什么。 如果要指定在点之前出现的前缀,可以使用“SELECT * FROM AS my_alias”,例如。
看来你的问题的答案是否定的,但是你可以使用的一个破解是分配一个虚拟列来分隔每个新表。 如果您循环使用脚本语言(如Python或PHP)中的列列表的结果集,则此function特别有效。
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
我意识到这并不完全回答你的问题,但如果你是一个编码器,这是一个很好的方式来分隔具有重复列名称的表。 希望这有助于某人。
我完全理解为什么这是必要的 – 至less对我来说,在需要连接很多表格(包括许多内部连接)的快速原型devise过程中,它是非常方便的。 只要第二个“joinedtable。*”字段通配符中的列名相同,主表的字段值就会被可join的值覆盖。 错误容易,令人沮丧和违反DRY时,必须反复手动指定表字段与别名…
这是一个PHP(Wordpress)函数,通过代码生成和一个如何使用它的例子来实现这个function。 在这个例子中,它用于快速生成一个自定义查询,该查询将提供通过高级自定义字段字段引用的相关的WordPress发布的字段。
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>"; }
输出:
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 ) )
我知道的唯一数据库是SQLite,具体取决于您使用PRAGMA full_column_names
和PRAGMA short_column_names
configuration的设置。 请参阅http://www.sqlite.org/pragma.html
否则,我可以推荐的是,如果在查询中键入列的名称太麻烦了,可以按顺序位置而不是列名来获取结果集中的列。
这是为什么使用SELECT *
是不好的做法的一个很好的例子 – 因为最终您将需要input所有的列名称。
我知道需要支持可能会改变名称或位置的列,但使用通配符会使得更难 ,更容易。
我和OP有同样的感觉 – 我有三个不同的表格,我join了几十个字段,其中一些具有相同的名称(即id,名称等)。 我不想列出每个字段,所以我的解决scheme是别名那些共享名称的字段,并使用select *为具有唯一名称的字段。
例如 :
表a:id,名称,field1,field2 …
表b:id,名称,field3,field4 …
selecta.id作为aID,a.name作为aName,a。 *,b.id作为bID,b.name作为bName,b。 * …..
当访问结果时,我们使用这些字段的别名,忽略“原始”名称。
也许不是最好的解决scheme,但它适用于我….我使用MySQL
不同的数据库产品会给你不同的答案; 但是如果你把这个东西放在很远的地方,你会伤到自己。 select你想要的列,然后给他们自己的别名,这样每个列的标识都是清晰的,你可以在结果中区分开来。
这个问题在实践中非常有用。 只需要在软件编程中列出每个明确的列,在那里你要特别小心地处理所有的情况。
想象一下,在debugging时,或者尝试使用DBMS作为日常的办公工具,而不是某些特定程序员抽象底层基础架构的可变实现,我们需要编写大量的SQL代码。 这种情况随处可见,如数据库转换,迁移,pipe理等。这些SQL中的大多数只会执行一次,永远不会再使用,给每一个列名称只是浪费时间。 不要忘了SQL的发明不仅仅是为了程序员的使用。
通常我会创build一个带有前缀列名的实用程序视图,这里是pl / pgsql中的函数,这并不容易,但可以将其转换为其他过程语言。
-- 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;
例子:
-- This will create a view "avp_person" with "p_" prefix to all column names. select * from mkaview('public', 'person', 'p_'); select * from avp_person;
这没有SQL标准。
然而,通过代码生成(在创build或更改表或在运行时按需提供),您可以非常容易地执行此操作:
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)
或者,您可以使用Red Gate SQL Refactor或SQL Prompt,它通过单击Tabbutton将您的SELECT *扩展到列列表中
所以在你的情况下,如果你inputSELECT * FROM A JOIN B …转到*,Tabbutton的结尾,瞧! 你会看到SELECT A.column1,A.column2,….,B.column1,B.column2 FROM A JOIN B
这不是免费的
不能这样做没有别名,只是因为,你是如何引用where子句中的一个字段,如果该字段存在于你join的2或3表中? 对于你正在尝试引用的哪一个,目前还不清楚。
我完全理解你的重复字段名称的问题。
我也需要这个,直到我编写我自己的函数来解决它。 如果您正在使用PHP,则可以使用它,或者使用您正在使用的语言对其进行编码,前提是您拥有以下设施。
这里的技巧是mysql_field_table()
返回表名和mysql_field_name()
结果中每一行的字段,如果mysql_num_fields()
得到的话,那么你可以把它们混合到一个新的数组中。
这是所有列的前缀;)
问候,
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; }
我通过重命名相关表中的字段来解决类似的问题。 是的,我有幸这样做,并明白,每个人都可能没有。 我在代表表名的表中为每个字段添加了前缀。 因此OP发布的SQL将保持不变 –
SELECT a.*, b.* FROM TABLE_A a JOIN TABLE_B b USING (some_id);
并仍然给出预期的结果 – 易于识别输出字段属于哪个表。
有两种方法可以让我们以可重用的方式来实现这一点。 一个是重命名所有的列与他们来自表的前缀。 我已经看过很多次了,但是我真的不喜欢它。 我发现这是多余的,会导致大量的input,并且当您需要覆盖列名不明的情况时,您总是可以使用别名。
另一种方式,我build议你在你的情况下做,如果你承诺看到这一点,是为每个表的名称创build视图。 然后你们反对这些意见,而不是表格。 这样,如果您愿意,可以自由使用*,如果您愿意,可以自由使用原始列名的原始表,并且还可以使后续查询更容易,因为您已经完成了视图中的重命名工作。
最后,我不清楚为什么你需要知道每个列是从哪个表来的。 这很重要吗? 最重要的是他们所包含的数据。 UserID是否来自User表或UserQuestion表并不重要。 当然,当你需要更新它的时候很重要,但是在那个时候,你应该已经知道你的模式足以确定它了。
如果担心模式更改,这可能适用于您:1.在涉及的所有表上运行“DESCRIBE表”查询。 2.使用返回的字段名称dynamic构造一个以您所选别名为前缀的列名称string。
对于那些使用MySQL C-API的人来说,有一个直接的答案。
鉴于SQL:
SELECT a.*, b.*, c.* FROM table_a a JOIN table_b b USING (x) JOIN table_c c USING (y)
'mysql_stmt_result_metadata()'的结果将您准备好的SQL查询中的字段定义为结构MYSQL_FIELD []。 每个字段包含以下数据:
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 */
注意字段:目录,表,org_name
您现在知道SQL中的哪些字段属于哪个模式(又名目录)和表。 这足以从多表sql查询中统一标识每个字段,而不必别名。
一个实际的产品SqlYOG被显示为以这样的方式使用这个确切的数据,当PK字段存在时,它们能够独立地更新多表连接的每个表。
从这个解决scheme开发,这是我将如何处理这个问题:
首先创build一个所有AS
语句的列表:
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
然后在你的查询中使用它:
EXEC('SELECT ' + @asStatements + ' FROM TABLE_A a JOIN TABLE_B b USING (some_id)');
但是,这可能需要修改,因为类似的东西只能在SQL Server中进行testing。 但是,这段代码在SQL Server中不能正常工作,因为USING不受支持。
请评论,如果你可以testing/更正这个代码例如MySQL。
select *通常会导致错误的代码,因为新的列往往会被添加,或者列的顺序在表格中相当频繁地改变,这通常会以非常微妙的方式破坏select *。 所以列出列是正确的解决scheme。
至于如何做你的查询,不知道有关mysql,但在sqlserver中,您可以从syscolumns中select列名称,并dynamic构buildselect子句。