Sql server 使用动态透视查询时多次指定该列?

Sql server 使用动态透视查询时多次指定该列?,sql-server,pivot,Sql Server,Pivot,假设我有两个表,table1和table2,我想用cte视图uvw\u TestView来透视它们 表1 id1 | name | locationCode ----|------|----------------- 1 | a | 3 2 | b | 1 3 | c | 2 表2 id2 | id1 | StudyName | dateStudy ----|-----|-----------|------ 1 | 1 | Math | 2015

假设我有两个表,
table1
table2
,我想用cte视图
uvw\u TestView
来透视它们

表1

id1 | name | locationCode
----|------|-----------------
1   | a    | 3
2   | b    | 1
3   | c    | 2
表2

id2 | id1 | StudyName | dateStudy
----|-----|-----------|------
1   | 1   | Math      | 2015-05-23
2   | 1   | Chemistry | 2015-06-20
3   | 2   | Math      | 2016-09-02
4   | 3   | Physics   | 2016-12-26
5   | 2   | Chemistry | 2017-01-05
6   | 2   | Math      | 2017-06-06
7   | 3   | Chemistry | 2018-02-22
这里的视图只是一个从
表1
学习的地方

如果将日期从
2015-05-01
过滤到
2017-01-01

id1 | name | Math       | Chemistry  | Physics 
1   | a    | 2015-05-23 | 2015-06-20 |   ---
2   | b    | 2016-09-02 |   ---      |   ---
3   | c    |   ---      |   ---      |   2016-12-26
很抱歉,我不能在这里显示真正的查询,但我尝试将其与之类似

我尝试在没有日期筛选器的情况下使用此查询

DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX), @dtDate1 DATETIME, @dtDate2 DATETIME;
SET @dtDate1 = '2015-05-01'
SET @dtDate2 = '2017-01-01'
SET @columns = N'';
SELECT @columns += N', ' + QUOTENAME(StudyName)
  FROM (SELECT DISTINCT t2.StudyName FROM dbo.table2 AS t2) AS x;

SET @sql = N'
WITH cte AS
(
    SELECT * FROM dbo.uvw_TestView WHERE idView = '001'
    UNION ALL
    SELECT a.* FROM dbo.uvw_TestView a INNER JOIN cte b ON a.ParentID = b.idView
SELECT * FROM
    (SELECT DISTINCT * FROM cte) ct
INNER JOIN (
    SELECT p.*, ' + STUFF(@columns, 1, 2, '') + '
    FROM
    (
        SELECT DISTINCT
            tb1.id1,
            tb1.name,
            tb2.dateStudy,
            tb2.StudyName
        FROM dbo.table1 AS tb1
        INNER JOIN dbo.table2 tb2 tb2
        ON tb1.id1 = tb2.id1
    ) AS j
    PIVOT
    (
      MIN(dateStudy) FOR StudyName IN ('
      + STUFF(REPLACE(@columns, ', [', ',['), 1, 1, '')
      + ')
    ) AS p) tbl ON tbl.id1 = ct.id1';
PRINT @sql;
EXEC sp_executesql @sql;
SELECT @columns += N', ' + QUOTENAME(StudyName)
  FROM (SELECT DISTINCT t2.StudyName FROM dbo.table2 AS t2) AS x;

SET @sql = N'
WITH cte AS
(
    SELECT * FROM dbo.uvw_TestView WHERE idView = '001'
    UNION ALL
    SELECT a.* FROM dbo.uvw_TestView a INNER JOIN cte b ON a.ParentID = b.idView
SELECT * FROM
    (SELECT DISTINCT * FROM cte) ct
INNER JOIN (
    SELECT p.*, ' + STUFF(@columns, 1, 2, '') + '
    FROM
    (
        SELECT DISTINCT
            tb1.id1,
            tb1.name,
            tb2.dateStudy,
            tb2.StudyName
        FROM dbo.table1 AS tb1
        INNER JOIN dbo.table2 tb2 tb2
        ON tb1.id1 = tb2.id1
    ) AS j
    PIVOT
    (
      MIN(dateStudy) FOR StudyName IN ('
      + STUFF(REPLACE(@columns, ', [', ',['), 1, 1, '')
      + ')
    ) AS p) tbl ON tbl.id1 = ct.id1 where tbl.dateStudy BETWEEN ''' + @dtDate1 +''' AND ''' + @dtDate2;
但是获取错误
列“Math”被多次指定为“tbl”。

我还尝试了日期过滤器

DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX), @dtDate1 DATETIME, @dtDate2 DATETIME;
SET @dtDate1 = '2015-05-01'
SET @dtDate2 = '2017-01-01'
SET @columns = N'';
SELECT @columns += N', ' + QUOTENAME(StudyName)
  FROM (SELECT DISTINCT t2.StudyName FROM dbo.table2 AS t2) AS x;

SET @sql = N'
WITH cte AS
(
    SELECT * FROM dbo.uvw_TestView WHERE idView = '001'
    UNION ALL
    SELECT a.* FROM dbo.uvw_TestView a INNER JOIN cte b ON a.ParentID = b.idView
SELECT * FROM
    (SELECT DISTINCT * FROM cte) ct
INNER JOIN (
    SELECT p.*, ' + STUFF(@columns, 1, 2, '') + '
    FROM
    (
        SELECT DISTINCT
            tb1.id1,
            tb1.name,
            tb2.dateStudy,
            tb2.StudyName
        FROM dbo.table1 AS tb1
        INNER JOIN dbo.table2 tb2 tb2
        ON tb1.id1 = tb2.id1
    ) AS j
    PIVOT
    (
      MIN(dateStudy) FOR StudyName IN ('
      + STUFF(REPLACE(@columns, ', [', ',['), 1, 1, '')
      + ')
    ) AS p) tbl ON tbl.id1 = ct.id1';
PRINT @sql;
EXEC sp_executesql @sql;
SELECT @columns += N', ' + QUOTENAME(StudyName)
  FROM (SELECT DISTINCT t2.StudyName FROM dbo.table2 AS t2) AS x;

SET @sql = N'
WITH cte AS
(
    SELECT * FROM dbo.uvw_TestView WHERE idView = '001'
    UNION ALL
    SELECT a.* FROM dbo.uvw_TestView a INNER JOIN cte b ON a.ParentID = b.idView
SELECT * FROM
    (SELECT DISTINCT * FROM cte) ct
INNER JOIN (
    SELECT p.*, ' + STUFF(@columns, 1, 2, '') + '
    FROM
    (
        SELECT DISTINCT
            tb1.id1,
            tb1.name,
            tb2.dateStudy,
            tb2.StudyName
        FROM dbo.table1 AS tb1
        INNER JOIN dbo.table2 tb2 tb2
        ON tb1.id1 = tb2.id1
    ) AS j
    PIVOT
    (
      MIN(dateStudy) FOR StudyName IN ('
      + STUFF(REPLACE(@columns, ', [', ',['), 1, 1, '')
      + ')
    ) AS p) tbl ON tbl.id1 = ct.id1 where tbl.dateStudy BETWEEN ''' + @dtDate1 +''' AND ''' + @dtDate2;
并获取错误
字符串或二进制数据将被截断。


那么,我如何解决这个错误以获得结果呢?

我看到您有一个
PRINT@sql语句。但是你看了这个问题了吗

错误
为“tbl”多次指定了列“Math”。
是由于此行引起的

SELECT p.*, ' + STUFF(@columns, 1, 2, '') + '
您的
将包含列列表,如
[化学],[数学]
p.*
实际上包含
透视
结果中的所有列。所以这些轴列是重复的


你只需做一个
选择*
,就足够了

您打印了正在执行的sql,但没有将其包含在帖子中?我看不出确切的问题,但几乎可以肯定是您使用
SELECT*
造成的。如果对联接执行
选择*
,则如果两个(或多个)表碰巧有一个或多个同名列,则会看到当前的错误消息。要解决此问题,请明确列出所需的列,并使用同名别名列。哦,这就是我的列重复的原因,谢谢,这很有用