我有两个表,Values
和SpecialValues
。
Values
有两列,RecordID
和ValueName
。
SpecialValues
是一个包含单行的表格,以及名为SpecialValueName1
,SpecialValueName2
,SpecialValueName3
等的30列。
此系统存在明显的数据库设计问题。
除此之外,有人可以向我解释如何查询SpecialValues
,以便我可以从表格中获取每一行的所有值的集合,并将其从Values
选择中排除吗?
可能有一些简单的方法可以做到这一点或为它创建一个View或者其他东西,但我认为看看这段代码可能暂时让我失望......
编辑:我想查询从给定表的每一行和每列中获取所有单个值(在本例中为SpecialValues
表),以便查询执行下次有人将另一列添加到SpecialValues
表时,无需更新。
答案 0 :(得分:1)
我可能会误解,但这不是吗?
SELECT * FROM Values
WHERE ValueName NOT IN (
SELECT SpecialValueName1 FROM SpecialValues
UNION SELECT SpecialValueName2 FROM SpecialValues
UNION SELECT SpecialValueName3 FROM SpecialValues
etc..
)
您当然可以将子查询转换为视图。
*编辑:
这很难看,但应该解决你的问题:
首先创建程序#1
CREATE PROCEDURE [dbo].[SP1]
As
DECLARE
@Query nvarchar(MAX),
@Table nvarchar(255),
@Columns nvarchar(255)
CREATE TABLE #TempTable (Value nvarchar(255))
SET @Table = 'SpecialValues'
SELECT [COLUMN_NAME]
FROM [INFORMATION_SCHEMA].[COLUMNS]
WHERE [TABLE_NAME] = @Table
DECLARE Table_Cursor CURSOR FOR
SELECT COLUMN_NAME
FROM [INFORMATION_SCHEMA].[COLUMNS]
WHERE [TABLE_NAME] = @Table
OPEN Table_Cursor
FETCH NEXT FROM Table_Cursor INTO @Columns
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO #TempTable EXEC SP2 @Columns = @Columns, @Table = @Table
FETCH NEXT FROM Table_Cursor INTO @Columns
END
CLOSE Table_Cursor
DEALLOCATE Table_Cursor
SELECT ValueName FROM Value WHERE Value NOT IN (SELECT * FROM #TempTable)
TRUNCATE TABLE #TempTable
DROP TABLE #TempTable
然后创建程序#2
CREATE PROCEDURE [dbo].[SP2]
@Columns nvarchar(255) = '',
@Table nvarchar(255)
AS
DECLARE
@Query nvarchar(MAX)
SET @Query = 'SELECT TOP 1 CONVERT(nvarchar, ' + @Columns + ') FROM ' + @Table
EXEC (@Query)
然后最后执行程序
EXEC SP1
答案 1 :(得分:1)
这会创建一个@SpecialValuesColumns
临时表来存储SpecialValues
中的所有列名
然后,它使用游标将每个列中的所有值插入另一个临时表#ProtectedValues
然后,它会使用NOT IN
查询将查询中的所有值排除到Values
。
这段代码很糟糕,我觉得编写它很糟糕,但它似乎是现在最开放的选择。
DECLARE @SpecialColumnsCount INT;
DECLARE @Counter INT;
DECLARE @CurrentColumnName VARCHAR(255);
DECLARE @ExecSQL VARCHAR(1024);
SET @Counter = 1;
CREATE TABLE #ProtectedValues(RecordID INT IDENTITY(1,1) PRIMARY KEY NOT NULL, Value VARCHAR(255));
DECLARE @SpecialValuesColumns TABLE (RecordID INT IDENTITY(1,1) PRIMARY KEY NOT NULL, ColumnName VARCHAR(255));
INSERT INTO @SpecialValuesColumns (ColumnName)
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'SpecialValues' AND
DATA_TYPE = 'varchar' AND
CHARACTER_MAXIMUM_LENGTH = 255
SELECT @SpecialColumnsCount = COUNT(*) FROM @SpecialValuesColumns
WHILE @Counter <= @SpecialColumnsCount
BEGIN
SELECT @CurrentColumnName = ColumnName FROM @SpecialValuesColumns WHERE RecordID = @Counter;
SET @ExecSQL = 'INSERT INTO #ProtectedValues (Value) SELECT ' + @CurrentColumnName + ' FROM SpecialValues'
EXEC (@ExecSQL)
SET @Counter = @Counter + 1;
END
SELECT * FROM Values WHERE ValueName NOT IN (SELECT ValueName COLLATE DATABASE_DEFAULT FROM #ProtectedValues)
DROP TABLE #ProtectedValues;
答案 2 :(得分:0)
您需要取消specialvalues
中的值。一种非常简单的方法是使用cross apply
语法:
select sv.value
from specialvalues sv cross apply
(values(sv.SpecialValueName1), (sv.SpecialValueName2), . . .
) sv(value)
where sv.value is not null;
您可以使用not in
,not exists
或left join
从列表中排除这些内容。
答案 3 :(得分:0)
你有什么方法可以剪切它,你必须在SpecialValues
中指定列,你可以使用一长串UNION
个查询来执行此操作,或者使用UNPIVOT
:
select SpecialValue
from (select SpecialValueName1,SpecialValueName2,SpecialValueName3 from #SpecialValues) p
unpivot (SpecialValue FOR ROW IN (SpecialValueName1,SpecialValueName2,SpecialValueName3))
AS unpvt
然后,您可以使用Values
NOT IN
的查询中
select * from [Values] where ValueName not in (
select SpecialValue
from (select SpecialValueName1,SpecialValueName2,SpecialValueName3 from #SpecialValues) p
unpivot (SpecialValue FOR ROW IN (SpecialValueName1,SpecialValueName2,SpecialValueName3))
AS unpvt
)