困难的T-SQL Join / Pivot

时间:2012-10-16 22:02:59

标签: .net sql tsql join

我说这个问题的原始方式对大多数人来说都没有用,所以我对它进行了大量修改。

我有一个遗留数据库,其架构我无法控制(也从未有过)。 db模式设计与提供程序无关,供非托管C ++使用,因此没有FK约束等。我出现并需要从.NET中使用它,并且还需要以与最初预期不同的方式呈现数据

以下是相关表格的架构(我用粗体/星号表示了这个问题的关键点数量):

CREATE TABLE [dbo].[Formats](
[GroupName] [varchar](255) NOT NULL,
**[BatchID] [bigint] NOT NULL,**
[SeriesNumber] [bigint] NOT NULL,
**[SequenceID] [bigint] NOT NULL,**
[SeqNum] [int] NOT NULL,
[FormatName] [varchar](50) NOT NULL

CREATE TABLE [dbo].[Fields](
[GroupName] [varchar](255) NOT NULL,
**[BatchID] [bigint] NOT NULL,**
**[SequenceID] [bigint] NOT NULL,**
[SeqNum] [int] NOT NULL,
**[FieldName] [varchar](50) NOT NULL,**
[FieldDisplayName] [varchar](50) NOT NULL,
[FieldValue] [ntext] NULL

格式:字段之间存在1:许多关系。

我需要查询格式行列表。挑战有几个:    +有一个复合外键。    +我需要将格式过滤到包含相关字段的子集。    +在内部连接到格式之前,相关字段必须匹配任意数量的过滤条件。

所以要走过这个: 存储过程接收以下表值参数:

_FieldDisplayName_  Field_Value
 Field 1             001
 Field 2             002

然后需要按这些值过滤Fields表。

由于我需要使用所有标准,而不仅仅是其中一个,我不知道如何使用它来检索有用的东西,当我不知道我有多少值时,或者FieldDisplayName值是什么。

@Joe Phillips非常聪明,能够看透混乱,并建议我需要转动桌子。就是这样:

修改 以下是为了转移数据,但我不确定它是否理想。在提供答案之前还在等待其他想法。

我没有使用TVP,而是使用临时表和动态SQL(是的,我看到了注入漏洞):

IF OBJECT_ID('[tempdb].[dbo].[#FilterFields]') is not null
Drop Table dbo.#FilterFields

CREATE Table #FilterFields (FieldDisplayName varchar(50), FieldValue nvarchar(max))
/* Just some example data */
INSERT INTO #FilterFields (FieldDisplayName, FieldValue) VALUES ('PTNUM', '011')
INSERT INTO #FilterFields (FieldDisplayName, FieldValue) VALUES('SITENUM', '001')

Declare @column_names varchar(max)
Declare @dynamic_pivot_query as varchar(max)

SELECT @column_names = Stuff((SELECT DISTINCT ',[' + FieldDisplayName + ']'
                FROM #FilterFields FOR xml path('')),1,1,'')

PRINT(@column_names)    

SET @dynamic_pivot_query =
'select * ' +
'from tempdb.dbo.#FilterFields ' +
'Pivot
(
MIN(
    FieldValue
    )
FOR FieldDisplayName IN (' + @column_names + ')
) as P'

PRINT(@dynamic_pivot_query)
EXEC(@dynamic_pivot_query)

2 个答案:

答案 0 :(得分:0)

SELECT  a.*, -- select on the rows you want to display by specifying
        b.*  -- their column name instead of using asterisk *
FROM    Formats a
        INNER JOIN Fields b
            ON  a.BatchID = b.BatchID AND
                a.SequenceID = b.SequenceID

答案 1 :(得分:0)

因为你有一个带有值列表的复合键(功能上),你需要利用子选择来利用IN。要做到这一点,您需要组合这些字段,这意味着至少要了解一些可能的数据,因为您希望以对每个密钥对唯一的方式组合它们。如果BatchID和SequenceID是设置长度字符串,那么只需添加它们就足够了。如果它们不同,您可能需要一个不会出现像破折号或符号的分隔符。我将在这里展示。

SELECT  *
FROM    Formats format 
WHERE   format.BatchID + '-' + format.SequenceID  IN 
    (SELECT field.BatchID + '-' + field.SequenceID
     FROM Fields field
           INNER JOIN #FilterFields filter
               ON filter.FieldDisplayName = field.FieldDisplayName AND
                  filter.FieldValue = field.FieldValue)

由于您在table参数上使用内连接,它将根据这些值的配对过滤字段表,并仅返回匹配的Fields表的组合键。