如何选择“行”值作为另一个表的列名?

时间:2019-03-20 14:17:32

标签: sql sql-server

所以我有一个查询,当我运行时会给我另一个表中列的名称。我要查询的表是我们软件中用户的列配置。它可以从显示3列更改为20列。该表将实际列的名称存储在数据库中。然后,我希望能够仅从该表中获取数据并仅基于返回的那些列名来查询另一个表。我很困惑如何做到这一点,因此当我为不同的用户运行查询时,查询将仅捕获他们保存在配置中的列。

我的第一个查询

SELECT field_name
FROM list_config
WHERE list_config.config_name = 'username'
  AND list_config.visible = 'Y';

返回列名:

field_name (header)

create_date       
customer_id       
id                
update_date       
update_user_id    
short_description    
ops_note          
create_user_id    
resp_user_id      
activity_status_id

然后我只想查询表work_order中仅由第一次查询产生的这些列。

我还是SQL的新手,任何帮助都很棒。我已经尝试过弄乱变量和一些过程,但是我现在还不够了解。

2 个答案:

答案 0 :(得分:1)

这是未经测试的,但是,这应该可以为您带来帮助:

DECLARE @SQL nvarchar(MAX);

SET @SQL = N'SELECT ' +
           STUFF((SELECT N',' + NCHAR(13) + NCHAR(10) +
                         N'       ' + QUOTENAME(field_name)
                  FROM list_config
                  WHERE list_config.config_name = 'username'
                    AND list_config.visible = 'Y'
                  --ORDER BY ??? --without an ORDER BY the order of the columns will be random/unpredictable
                  FOR XML PATH(N''),TYPE).value(N'.','nvarchar(MAX)'),1,10,N'') + NCHAR(13) + NCHAR(10) +
           N'FROM work_order;';
--PRINT @SQL; --your debugging best friend
EXEC sp_executesql @SQL;

如果需要传递参数,请确保参数化sp_execute语句; 请勿将参数值插入动态语句。

如果要验证列名是真实列名,则可以使用EXISTS

DECLARE @SQL nvarchar(MAX);

SET @SQL = N'SELECT ' +
           STUFF((SELECT ',' + NCHAR(13) + NCHAR(10) +
                         N'       ' + QUOTENAME(lc.field_name)
                  FROM list_config lc
                  WHERE lc.config_name = 'username'
                    AND lc.visible = 'Y'
                    AND EXISTS (SELECT 1
                                FROM INFORMATION_SCHEMA.COLUMNS C
                                WHERE C.COLUMN_NAME = lc.field_name
                                  AND C.TABLE_NAME = N'Work_order')
                  --ORDER BY ???
                  FOR XML PATH(N''),TYPE).value(N'.','nvarchar(MAX)'),1,10,N'') + NCHAR(13) + NCHAR(10) +
           N'FROM work_order;';
--PRINT @SQL; --your debugging best friend
EXEC sp_executesql @SQL;

此答案的工作方式是以“定界”格式构建所有列的列表。因此,真正的“魔术”位于FOR XML PATH中,因此我们将从子查询开始。

FOR XML PATH基本上按照提示进行操作,它将结果集转换为XML。我们可以使用此功能来连接表work_order的结果集中的所有值。我给每个值加上N',' + NCHAR(13) + NCHAR(10) + N' '(这很重要)。这似乎有点奇怪(有些仅使用','),所以我将进行解释。逗号是简单的逗号,在每个列名之间我们需要其中之一。 NCHAR(13) + NCHAR(10)是回车符(Unicode字符13)和换行符(Unicode字符10)。然后我们有一些空白。我这样做纯粹是为了格式化,格式化的动态SQL比格式化不好的 更容易解决问题。

然后我们有STUFFSTUFF用于删除field_name的每个值的第一个前缀(这就是为什么我说作为前缀很重要的原因)。 STUFF的第二个参数(在这种情况下为1)是开始替换的位置,第三个参数是要替换的字符数(因此,字符1-10)。最后一个参数是用(''替换那些字符的内容。这样就用N',' + NCHAR(13) + NCHAR(10) + N' '替换了第一个前缀('')。

答案 1 :(得分:0)

这是另一种方法(未经测试)

declare @query nvarchar(1000) = ''

select @query = @query+',['+field_name+']'
FROM list_config
WHERE list_config.config_name = 'username'
  AND list_config.visible = 'Y';

 set @query =substring(@query,2,len(@query))

 set @query ='select '+@query + ' from work_order'

exec (@query)

您可以以此构建任何类型的脚本