【问题标题】:Difficult T-SQL Join/Pivot困难的 T-SQL 连接/透视
【发布时间】:2012-10-16 22:02:58
【问题描述】:

我最初提出这个问题的方式对大多数人来说都没有帮助,所以我对其进行了重大修改。

我有一个旧数据库,其架构我无法控制(也从来没有)。 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

Formats:Fields 之间存在 1:Many 的关系。

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

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

_FieldDisplayName_  Field_Value
 Field 1             001
 Field 2             002

然后它需要按这些值过滤字段表。

由于我需要使用所有标准,而不仅仅是其中一个标准,所以我不知道如何使用它来检索有用的东西以加入,当我不知道我有多少值时,或者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)

【问题讨论】:

  • 我认为您正在寻找数据透视?
  • 其实,这是一个有趣的想法——我没有想到这一点。让我深入研究一下。我想我之前什至没有意识到 T-SQL 有一个数据透视函数。
  • 你能发布一些示例数据和预期的输出吗?目前还不太清楚(至少对我而言)您在寻找什么。
  • @SebastianMeine,我明天一定会更全面地更新帖子;我必须在妻子杀了我的前一晚签字:)

标签: .net sql tsql join


【解决方案1】:
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

【讨论】:

    【解决方案2】:

    因为您有一个包含值列表的复合键(功能上),所以您希望通过子选择来利用 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 参数上使用了内部联接,因此它将根据这些值的配对过滤字段表,并仅返回匹配的字段表的组合键。

    【讨论】:

    • 这确实是我开始的地方,但请记住,我基本上是根据标准列表(由 FieldDisplayName 和 FieldValue 的键值对组成)过滤格式表。因此,所需的连接数是任意的。
    • 由于复合键,这变得更加困难。我会看看我是否能想出一个替代方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2016-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-09
    相关资源
    最近更新 更多