你会怎么写这个查询?

时间:2009-01-28 21:17:03

标签: sql refactoring rewrite

我希望将以下查询重构为更具可读性和可修改性的内容。前半部分与第二部分相同,但查询的数据库除外(表名相同但是。)

  SELECT
    Column 1 AS c1,
    ...
    Column N AS cN
  FROM
    database1.dbo.Table1

UNION

  SELECT
    'Some String' as c1,
    ...
    NULL as cN
  FROM
    database1.dbo.Table2

UNION

  SELECT
    Column 1 AS c1,
    ...
    Column N AS cN
  FROM
    database2.dbo.Table1

UNION

  SELECT
    'Some String' as c1,
    ...
    NULL as cN
  FROM
    database2.dbo.Table2

此查询是DRY的定义,并呼吁我重写,但我不知道如何!

编辑:我们不能使用linq,我们希望得到明显的结果;我希望使查询的物理文件大小更小,而不是返回结果。

编辑:我要查询的数据库是专有的ERP数据库。重组它不是一种选择。

8 个答案:

答案 0 :(得分:3)

我会在这里出去,并根据你给我们的信息说出来;

这就好了,

答案 1 :(得分:2)

我看到的一个性能提示是使用UNION ALL而不是UNION,除非您有意想要不同的记录。一个简单的UNION将消除重复,这需要时间。 UNION ALL不这样做。

你可以用动态SQL和循环重写它,但我认为结果会更糟。如果有足够的重复代码来证明动态sql方法的合理性,那么我想这可能是合理的。

或者,你是否考虑过将存储过程中的逻辑移到像LINQ这样的东西?对于很多人来说,这不是一个选择,所以我只想问。

最后一点:抵制修复未破坏的冲动只是为了让它看起来更干净。如果清理将有助于维护,验证等,那就去做吧。

答案 2 :(得分:2)

这是一个非常标准的SQL模式。有时很容易将OOP /程序代码原则(如DRY)转移到SQL,但它们不一定是可转换的概念。

请注意,您可以轻松地查询查询的整个逻辑设计,而不是通过子模块进行搜索。如果其中一个子表达式有一个额外的列,或列反转,它会突然出现。这基本上是一个非常简单的SQL语句,可以作为一个执行单元,在那里分解它会使它混乱。

当您进行调试时,能够使用编辑器的文本突出显示选项来选择性地执行语句的某些部分是非常方便的 - 这是一种在过程代码中不存在的技术。 OTOH,如果它们被分散到视图等中,它可能会变得混乱,试图追踪所有碎片。即使CTE也会使这不方便。

答案 3 :(得分:1)

有什么问题?太长?太重复了?

有时你会得到丑陋的SQL - 你无能为力。

除非您想使用单独的视图然后将它们组合在一起,否则我看不到任何清理方法。

答案 4 :(得分:1)

我投票支持视图,这会产生足够的零开销(好吧,可能是一个很小的编译时成本,但应该是全部)。那么你的过程就变成了

的形式
SELECT * FROM database1.view1
UNION
SELECT * FROM database1.view2
UNION
SELECT * FROM database2.view1
UNION
SELECT * FROM database2.view2

我不确定我是否想要进一步浓缩它,尽管我希望大多数平台能够容忍它。

答案 5 :(得分:0)

在动态SQL主题上 - 这是一个示例 - 不确定它是否更好。好处是你只需要编写一次SELECT列表。

DECLARE @Select1 varchar(1000)
DECLARE @Select2 varchar(1000)

DECLARE @SQL varchar(4000)


SET @Select1 = 'SELECT
    Column 1 AS c1,
    ...
    Column N AS cN'


SET @Select2 = 'SELECT
    ''Some String'' as c1,
    ...
    NULL as cN'


SET @SQL = @Select1 + ' FROM database1.dbo.Table1 '

SET @SQL = @SQL + ' UNION ' + @Select2 + ' FROM database1.dbo.Table2 '

SET @SQL = @SQL + ' UNION ' + @Select1 + ' FROM database2.dbo.Table1 '

SET @SQL = @SQL + ' UNION ' + @Select2 + ' FROM database2.dbo.Table2 '


EXEC @SQL

答案 6 :(得分:0)

如果您的所有过程都是这样的 - 您可能遇到了架构问题。

你对table2的所有调用是否只有一个有用的字段? (因为UNION,最终只有一行?)

我完全赞同为这项工作使用参数化动态SQL和/或代码生成的想法,甚至可以使用INFORMATION_SCHEMA动态生成列列表。这不是你需要的,但它是一个开始(你可能生成一个数据库和表的表):

DECLARE @template AS varchar(MAX)
SET @template = 'SELECT {@column_list} FROM {@database_name}.dbo.{@table_name}'
DECLARE @column_list AS varchar(MAX)

SELECT @column_list = COALESCE(@column_list + ',', '') + COLUMN_NAME
FROM database1.dbo.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @table_name
ORDER BY ORDINAL_POSITION

DECLARE @sql AS varchar(MAX)
SET @sql = @template
SET @sql = REPLACE(@sql, '{@column_list}', @column_list)
SET @sql = REPLACE(@sql, '{@database_name}', @database_name)
SET @sql = REPLACE(@sql, '{@table_name}', @table_name)

答案 7 :(得分:0)

根据返回的行数,您可能最好在选择上使用UNION ALL,并在其周围选择不同的查询。 我以前见过类似的问题,并为两种不同的风格制定了不同的执行计划

SELECT DISTINCT subquery.c1, subquery.cN
FROM
(
SELECT Column 1 AS c1, Column N AS cN FROM database1.dbo.Table1
UNION ALL
SELECT 'Some String' as c1, NULL as cN FROM database1.dbo.Table2
UNION ALL
SELECT Column 1 AS c1, Column N AS cN FROM database2.dbo.Table1
UNION ALL
SELECT 'Some String' as c1, NULL as cN FROM database2.dbo.Table2
) subquery