目标:保持一年中每个月的学生班级排名表
Haves:我的代码为我提供了列
StudentID; '+@DateTXT+'
DateTXT是动态变量,返回我正在运行代码的任何月份。
需要:我正在尝试使用MERGE,UPDATE,INSERT函数来运行代码并建立一个表格:
| StudentID | Jan |
| 56789 | 2 |
| 12345 | 7 |
然后每个月我都会在永久表中添加一个新的月份列:
EXEC('ALTER TABLE StudentRanking
ADD ' + @DateTXT + ' smallint NOT NULL DEFAULT(999)')
| StudentID | Jan | Feb |
| 56789 | 2 | 999 |
| 12345 | 7 | 999 |
我将在2月再次运行排名代码并将其保存到临时表中,我将用它来合并,更新,插入StudentRanking表:
| StudentID | Feb |
| 56789 | 3 |
(note.. student 12345 doesn't come up)
所以我想最终得到一个运行列表:
EXEC('
MERGE StudentRanking AS TARGET
USING ##TEMPDB2 AS SOURCE ON (TARGET.StudentID = SOURCE.StudentID)
WHEN MATCHED AND TARGET.' + @DateTXT + ' <> SOURCE.' + @DateTXT + '
THEN UPDATE SET TARGET.' + @DateTXT + ' = SOURCE.' + @DateTXT + '
WHEN NOT MATCHED BY TARGET THEN
INSERT (StudentID, ' + @Rank_TXT + ')
VALUES (SOURCE.StudentID, SOURCE.' + @Rank_TXT + ') ')
| StudentID | Jan | Feb |
| 56789 | 2 | 3 |
| 12345 | 7 |null |
问题:有些学生离开了学校,因此在前几个月创建了一个空排名(例如12345在2月没有排名),所以当我尝试从临时表中插入结果时,我得到了这个错误:
SQL Server Database Error: Cannot insert the value NULL into column 'Feb', table 'tempdb.dbo.##TEMPDB'; column does not allow nulls. UPDATE fails.
我可以做一个ISNULL(排名,0),但我宁愿有零而不是0
答案 0 :(得分:0)
始终打开另一种更好的方法@GarethD!
我实际上是通过这样做来实现的:
EXEC('ALTER TABLE StudentRanking
ADD ' + @Date_TXT + ' smallint DEFAULT(null)')
WHEN MATCHED AND TARGET.' + @Date_TXT + ' IS NULL
THEN UPDATE SET TARGET.' + @Date_TXT + ' = SOURCE.' + @Date_TXT + '
答案 1 :(得分:0)
快速修复是使列不可为空。值得指出的是,这种解决方案不能很好地扩展。更具可扩展性的方法是使用正确规范化的表格,其中StudentID
和Month
构成您的主键。
然后你有类似的东西:
CREATE TABLE dbo.StudentRanking
(
Date DATE NOT NULL,
StudentID INT NOT NULL,
Score INT NOT NULL,
CONSTRAINT PK_StudentRanking__StudentID_Date PRIMARY KEY(Date, StudentID),
);
然后,您可以在此基础上创建一个视图,以获得您想要的格式的表格:
CREATE VIEW dbo.StudentRankingByYear
WITH SCHEMABINDING
AS
SELECT StudentID,
Year = DATEPART(YEAR, Date),
Jan = SUM(CASE WHEN DATEPART(MONTH, Date) = 1 THEN Score END),
Feb = SUM(CASE WHEN DATEPART(MONTH, Date) = 2 THEN Score END),
Mar = SUM(CASE WHEN DATEPART(MONTH, Date) = 3 THEN Score END),
Apr = SUM(CASE WHEN DATEPART(MONTH, Date) = 4 THEN Score END),
May = SUM(CASE WHEN DATEPART(MONTH, Date) = 5 THEN Score END),
Jun = SUM(CASE WHEN DATEPART(MONTH, Date) = 6 THEN Score END),
Jul = SUM(CASE WHEN DATEPART(MONTH, Date) = 7 THEN Score END),
Aug = SUM(CASE WHEN DATEPART(MONTH, Date) = 8 THEN Score END),
Sep = SUM(CASE WHEN DATEPART(MONTH, Date) = 9 THEN Score END),
Oct = SUM(CASE WHEN DATEPART(MONTH, Date) = 10 THEN Score END),
Nov = SUM(CASE WHEN DATEPART(MONTH, Date) = 11 THEN Score END),
Dec = SUM(CASE WHEN DATEPART(MONTH, Date) = 12 THEN Score END)
FROM dbo.StudentRanking
GROUP BY StudentID, DATEPART(YEAR, Date);
GO
您甚至可以在此基础上创建一个索引视图,以获得您想要的格式(如果您确实需要,但查询应该执行得足够好,而不需要视图),唯一的区别是你不能有空列,所以缺少的月份必须显示为0:
CREATE VIEW dbo.StudentRankingByYear
WITH SCHEMABINDING
AS
SELECT StudentID,
Year = DATEPART(YEAR, Date),
Jan = SUM(CASE WHEN DATEPART(MONTH, Date) = 1 THEN Score ELSE 0 END),
Feb = SUM(CASE WHEN DATEPART(MONTH, Date) = 2 THEN Score ELSE 0 END),
Mar = SUM(CASE WHEN DATEPART(MONTH, Date) = 3 THEN Score ELSE 0 END),
Apr = SUM(CASE WHEN DATEPART(MONTH, Date) = 4 THEN Score ELSE 0 END),
May = SUM(CASE WHEN DATEPART(MONTH, Date) = 5 THEN Score ELSE 0 END),
Jun = SUM(CASE WHEN DATEPART(MONTH, Date) = 6 THEN Score ELSE 0 END),
Jul = SUM(CASE WHEN DATEPART(MONTH, Date) = 7 THEN Score ELSE 0 END),
Aug = SUM(CASE WHEN DATEPART(MONTH, Date) = 8 THEN Score ELSE 0 END),
Sep = SUM(CASE WHEN DATEPART(MONTH, Date) = 9 THEN Score ELSE 0 END),
Oct = SUM(CASE WHEN DATEPART(MONTH, Date) = 10 THEN Score ELSE 0 END),
Nov = SUM(CASE WHEN DATEPART(MONTH, Date) = 11 THEN Score ELSE 0 END),
Dec = SUM(CASE WHEN DATEPART(MONTH, Date) = 12 THEN Score ELSE 0 END),
Records = COUNT_BIG(*)
FROM dbo.StudentRanking
GROUP BY StudentID, DATEPART(YEAR, Date);
GO
CREATE UNIQUE CLUSTERED INDEX UQ_StudentRankingByYear__StudentID_Year
ON dbo.StudentRankingByYear (StudentID, Year);
答案 2 :(得分:-1)
将ALTER TABLE更改为:
EXEC('ALTER TABLE StudentRanking
ADD ' + @DateTXT + ' smallint NULL')
假设下来的选票是因为我没有提供标准化的替代方案,我建议使用PIVOT来解决这类问题。
设定:
CREATE TABLE dbo.StudentRanking
(
MonthID CHAR(3) NOT NULL,
StudentID INT NOT NULL,
Score INT NOT NULL,
CONSTRAINT PK_StudentRanking__StudentID_Date PRIMARY KEY(MonthID, StudentID),
);
INSERT INTO dbo.StudentRanking VALUES ('JAN', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('FEB', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('MAR', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('APR', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('MAY', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('JUN', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('JUL', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('AUG', 56321, 3)
INSERT INTO dbo.StudentRanking VALUES ('SEP', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('OCT', 56321, 3)
INSERT INTO dbo.StudentRanking VALUES ('NOV', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('DEC', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('JAN', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('FEB', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('MAR', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('APR', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('MAY', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('JUN', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('JUL', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('AUG', 56821, 2)
INSERT INTO dbo.StudentRanking VALUES ('SEP', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('OCT', 56821, 2)
INSERT INTO dbo.StudentRanking VALUES ('NOV', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('DEC', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('JAN', 56021, 3)
INSERT INTO dbo.StudentRanking VALUES ('FEB', 56021, 3)
INSERT INTO dbo.StudentRanking VALUES ('MAR', 56021, 3)
INSERT INTO dbo.StudentRanking VALUES ('APR', 56021, 3)
INSERT INTO dbo.StudentRanking VALUES ('MAY', 56021, 3)
INSERT INTO dbo.StudentRanking VALUES ('JUN', 56021, 4)
INSERT INTO dbo.StudentRanking VALUES ('JUL', 56021, 5)
查询
SELECT * FROM StudentRanking
PIVOT (SUM(Score) FOR MonthID IN (JAN, FEB, MAR, APR,
MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC)) AS PVT
结果
在这种情况下,SUM(SCORE)是无害的,因为每个学生每月不会有多个记录。它只是让PIVOT知道要解决的问题。