SQL Server:查询名称存储在列中的表的最佳方法是什么?

时间:2015-09-06 16:52:15

标签: sql sql-server

我想整理一个查询但是为了避免使用游标。我们有PDF文件存储在多个表中。每张桌子一年。所以我们有表名,如:

"Files_2012", "Files_2013", "Files_2014", etc.  

然后我们有一个主表(称为Files),其中包含存储文件的表。

这是布局:

=======================================
 FILES
=======================================
 FileId | RecordId | FileTableName
---------------------------------------
 104    |  7108162 |  Files_2013
 105    |  7108162 |  Files_2014
 106    |  7108162 |  Files_2013

年度表格如下:

=======================================
 FILES_2013
=======================================
 FileId | FileData (varbinary
---------------------------------------
 104    |  0x255044462D312E340A25E2E3CFD30D...
 106    |  0x897444462D312E340A25E2E3CFD30D...

=======================================
 FILES_2014
=======================================
 FileId | FileData (varbinary
---------------------------------------
 105    |  0x556044462D312E340A25E2E3CFD30D...

我的查询需要根据RecordId返回记录。因此,在此示例中,所有3个Files.RecordId值都相同。我需要为所有3条记录返回FileData列,如下所示:

=======================================
 My returned records
=======================================
 FileId | FileData (varbinary
---------------------------------------
 104    |  0x255044462D312E340A25E2E3CFD30D...
 105    |  0x556044462D312E340A25E2E3CFD30D...
 106    |  0x897444462D312E340A25E2E3CFD30D...

我该怎么做?如果它有帮助,这是我到目前为止的查询,虽然我可能会离开。我将FileTableName值存储到临时表和&我希望能以这种方式与他们合作,但在此之后我就陷入了困境:

DECLARE @recordId INT

CREATE TABLE #tmpFiles (FileId int, FileTableName varchar(100), FileData varbinary(max))

SET @recordId = 7108162

INSERT INTO #tmpFiles (FileId, FileTableName)
    SELECT FileId, FileTableName 
    FROM dbo.Files 
    WHERE RecordId = @recordId    

UPDATE t
SET t.FileData = f.FileData
FROM #tmpFiles t
INNER JOIN Files_2013 f ON t.FileId = f.FileId

感谢您提供的任何帮助。

1 个答案:

答案 0 :(得分:3)

假设您事先知道表名,可以使用UNION ALL

DECLARE @recordId INT = 7108162;

WITH cte(FileId, FileData, Year) AS
(
   SELECT FileId , FileData, 2012 AS [Year]
   FROM FILES_2012
   UNION ALL
   SELECT FileId , FileData, 2013
   FROM FILES_2013
   UNION ALL
   SELECT FileId , FileData, 2014 
   FROM FILES_2014
)
SELECT c.*
FROM FILES f
JOIN cte c
  ON f.FileId = c.FileId
WHERE f.RecordId = @RecordId;

如果你不知道表名(我怀疑它们有共同的名称模式),你需要使用Dynamic-SQL但重新考虑不同的选项。

阅读The Curse and Blessings of Dynamic SQL by Erland Sommarskog

  

SELECT * FROM sales + @yymm

     

这是前一种情况的变体,其中有一套   实际上描述同一实体的表。 所有表都有   相同的列,名称包括一些分区组件,   通常是年份,有时也是月份。新表创建为   新年/月开始。

     

在这种情况下,每个表写一个存储过程并不是真的   可行。至少,因为用户可能想要指定日期   搜索的范围,所以即使每个表有一个程序,你也可以   仍然需要动态调度员。

     

现在,让我们说清楚:这是一个有缺陷的桌面设计。你   每个月不应该有一个销售表,你应该有一个   sales表和表名中出现的月份应该是   联合销售表中主键的第一列。但是你   可能会陷入无法轻易更改的遗留应用程序   桌子设计。而且,诚然,有些情况下   分区是有道理的。该表可能很大(比如说超过10 GB)   大小),或者您希望能够快速老化旧数据。但就是这样   你应该正确分区。

     

在下文中,我将介绍三种处理方法   不使用动态SQL进行分区。

     

可能的解决方案:

     
      
  • 分区表
  •   
  • 观看和分区视图
  •   
  • 兼容性视图
  •