【问题标题】:Read columns in SQL tables which are the result of another query读取 SQL 表中的列,这些列是另一个查询的结果
【发布时间】:2020-08-26 14:34:09
【问题描述】:

我需要检查所有主键列是否有所有值都为大写

所以,我有一个第一个请求,它返回我作为 PK 一部分的表字段对。

SELECT table_name, field_name FROM dico WHERE pkey > 0;

dico 是一些提供该信息的表。无需在 SQL Schema 中查找...)

而且,对于上面第一个查询中列出的所有这些对 tx/fx,我需要查找不会大写的值。

SELECT DISTINCT 't1', 'f1', f1 FROM t1 WHERE f1 <> UPPER(f1) UNION ALL
SELECT DISTINCT 't2', 'f2', f2 FROM t2 WHERE f2 <> UPPER(f2) UNION ALL
...
SELECT DISTINCT 'tn', 'fn', fn FROM tn WHERE fn <> UPPER(fn);

(我将表名和字段名作为“字符串”放在输出中,以便知道错误值的来源。)

如您所见,我确实有这两个请求的代码,但我不知道如何将它们组合起来(如果可能,以适用于 SQL Server 和 Oracle 的通用方式)。

你能给我一些关于如何完成它的想法吗?

【问题讨论】:

  • 添加只传递大写值的约束。
  • 这相当棘手,因为 Oracle 默认情况下区分大小写,但 SQL Server 不区分。
  • 我无法添加约束。我需要检查里面有什么——有些东西是通过外部系统、Excel 文件等导入的。
  • @GordonLinoff 如果我需要编写 2 个不同的查询,因为区分大小写,就这样吧。这不是一个硬性要求,而是一个很好的要求(在两个环境中都可以使用相同的请求)。

标签: sql sql-server oracle union dynamic-sql


【解决方案1】:

我能想到的一种方法是使用包含循环的语句块。

不幸的是,每个不同的数据库系统的语句块结构都会有所不同(SQL Server 的结构对于 Oracle 会有所不同)。

我在下面进一步使用 SQL Server 编写了一个示例(小提琴链接位于:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=85cd786adf32247da1aa73c0341d1b72)。

以防万一,动态查询变得很长(可能比varchar 的限制长,即8000 个字符),SQL Server 有varchar(max),最多可容纳2GB (https://docs.microsoft.com/en-us/sql/t-sql/data-types/char-and-varchar-transact-sql?view=sql-server-ver15)。这可以用于@DynamicQuery,替换下面示例中的VARCHAR(3000)(修改/替代小提琴链接,只是为了表明该数据类型确实存在并且可以使用,位于:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=7fbb5d130aad35e682d8ce7ffaf09ede)。

请注意,该示例未使用您的确切查询,因为我无法访问与您拥有的完全相同的数据(例如,我无法使用 dico 表测试该示例,因为我无权访问该表桌子)。 但是,我制作了这个示例,以便它使用与您的查询类似的基本逻辑结构,以便稍后可以对其进行自定义以满足您的确切需求/场景(例如,通过更改表名和字段名以匹配那些您可以使用,也可以根据需要添加WHERE 子句)。

在示例中,您的第一个查询将立即运行,结果将由游标处理。

之后,一个循环(使用WHILE 语句/结构)将遍历游标以获取第一个查询的结果以动态构建第二个查询(插入第一个查询的表名和字段名)。

请注意,此时,第二个查询仍在构建中,尚未运行。

最终,循环结束后,生成/编译的第二个查询将运行/执行(使用EXEC 命令)。

-- START of test data creation.
create table TableA
( message varchar(200)
);

insert into TableA([message]) values ('abc');
insert into TableA([message]) values ('def');

create table TableB
( message varchar(200)
);

insert into TableB([message]) values ('ghi');
insert into TableB([message]) values ('jkl');
-- END of test data creation.



-- START of dynamic SQL
declare @TableAndFieldDetails CURSOR
declare @TableName VARCHAR(50)
declare @FieldName VARCHAR(50)
declare @DynamicQuery VARCHAR(3000) = ''
begin
  SET @TableAndFieldDetails = CURSOR FOR
  -- START of the 1st query
  SELECT  [INFORMATION_SCHEMA].COLUMNS.TABLE_NAME,
          [INFORMATION_SCHEMA].COLUMNS.COLUMN_NAME
  FROM    INFORMATION_SCHEMA.COLUMNS
  WHERE   INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME LIKE '%message%'
  -- END of the 1st query

  -- START of dynamically building the 2nd query
  OPEN @TableAndFieldDetails
  FETCH NEXT FROM @TableAndFieldDetails INTO @TableName, @FieldName
  WHILE @@FETCH_STATUS = 0
  BEGIN
    IF @DynamicQuery <> ''
    BEGIN
      SET @DynamicQuery += ' UNION ALL '
    END

    -- The one line right below is each individual part/element of the 2nd query
    SET @DynamicQuery += 'SELECT ''' + @TableName + ''', ''' + @FieldName + ''', ' + @FieldName + ' FROM ' + @TableName

    FETCH NEXT FROM @TableAndFieldDetails INTO @TableName, @FieldName
  END
  CLOSE @TableAndFieldDetails
  DEALLOCATE @TableAndFieldDetails
  -- END of dynamically building the 2nd query

  EXEC (@DynamicQuery)
end
-- END of dynamic SQL

【讨论】:

  • 亲爱的@peter.aryanto,我的印象是这可行——适合我的情况。但是,3,000 的大小限制太小了。连5000都不够(PK很多,文字很快就很长了)……想改成text也不成功:The text, ntext, and image data types are invalid for local variables.
  • 我确实想过你可能有这么长的查询链。这就是我选择 varchar(最大 8000)而不是 nvarchar(最大 4000)的原因。 8000个字符就够了吗?如果这还不够,SQL Server 的 varchar(max) 有 2GB 限制 (docs.microsoft.com/en-us/sql/t-sql/data-types/…)。
  • 我使用了varchar(max),但仍然被阻止。将EXEC 替换为PRINT 时,我看到字符串被剪切为8,000 个字符!?
  • 查看长字符串,请使用PRINT LEN(@DynamicQuery)EXEC ('select ''' + @DynamicQuery + '''')。不幸的是,PRINT 命令/语句将截断 8,000 个字符的长字符串(已在此处讨论:stackoverflow.com/questions/7392161/t-sql-varcharmax-truncated/…)。
  • 快速复查以证明它没有被截断:dbfiddle.uk/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多