1

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

  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 数据库。重组它不是一种选择。

4

8 回答 8

3

我要在这里冒个险,说,根据你给我们的信息;

这就像它会得到的一样好

于 2009-01-28T21:22:32.607 回答
2

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

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

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

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

于 2009-01-28T21:22:29.250 回答
2

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

请注意,您可以轻松地了解查询的整个逻辑设计,而不是通过子模块进行搜索。如果其中一个子表达式有一个额外的列,或者列颠倒了,它就会突出。这基本上是一个非常简单的 SQL 语句,可以作为一个执行单元来理解,分解它会混淆它。

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

于 2009-01-28T23:09:25.680 回答
1

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

有时你会得到丑陋的 SQL——你对此无能为力。

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

于 2009-01-28T21:23:20.217 回答
1

我投票赞成意见,这会带来几乎足够的零开销(好吧,也许编译时间成本很小,但这应该就是全部了)。然后你的 procs 就变成了某种形式

SELECT * FROM database1.view1
UNION
SELECT * FROM database1.view2
UNION
SELECT * FROM database2.view1
UNION
SELECT * FROM database2.view2

我不确定我是否想进一步压缩它,尽管我预计大多数平台都会容忍它。

于 2009-01-28T21:32:49.887 回答
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
于 2009-01-28T21:42:26.747 回答
0

如果你所有的 proc 看起来像这样 - 你可能遇到了架构问题。

您对 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)
于 2009-01-28T21:59:59.473 回答
0

根据返回的行数,您最好在选择上使用 UNION ALL 并围绕它进行选择不同的查询。我以前见过类似的问题,并且对两种不同的样式有不同的执行计划

SELECT DISTINCT subquery.c1, subquery.cN
从
(
SELECT Column 1 AS c1, Column N AS cN FROM database1.dbo.Table1
联合所有
SELECT 'Some String' as c1, NULL as cN FROM database1.dbo.Table2
联合所有
SELECT Column 1 AS c1, Column N AS cN FROM database2.dbo.Table1
联合所有
SELECT 'Some String' as c1, NULL as cN FROM database2.dbo.Table2
) 子查询
于 2009-01-29T11:23:49.843 回答