Схема этой базы данных нечетная;Все данные разбиты по типам и хранятся в соответствующих таблицах.Когда требуется доступ к «таблице», она должна быть сшита вместе, поля по идентификатору таблицы, значения по идентификатору поля.Он медленный, и в основном о нем позаботились сторонние сценарии спагетти.
У меня есть несколько таблиц, отформатированных примерно так:
dbo.TagSource:
TagSourceId | Table Name | ...
------------------------------------
01 Table 1
02 Table 2
dbo.Tag:
TagId | TagSourceId | Field Name | RawTableName | ...
------------------------------------------------------
11 01 Name dbo.StringValue
12 01 Age dbo.IntegerValue
13 01 Balance dbo.DecimalValue
14 01 Document dbo.FileValue
15 02 Name ExternalTable1
16 02 Height ExternalTable1
17 02 Occupation ExternalTable2
dbo. [String / Integer / Decimal / File / ...] Таблицы значений:
ValueId | TagId | Value
-------------------------------
101 11 John Smith
102 11 Jane Smith
103 11 John Doe
104 11 Jane Doe
105 11 Thanos
ЦЕЛЬ: Чтобы создатьСценарий запроса TSQL (хранимая процедура / функция / представление), которому задан TagSourceID в качестве параметра / объявленной переменной, возвращает соответствующую таблицу.В конце концов, это будет использоваться для создания представлений, пока у меня не будет полосы пропускания для замены и замены схемы БД.
Каков оптимальный способ сделать это? Это сложно, так как числополя в каждой таблице являются динамическими, а определения столбцов неизвестны.
Попытки: Я пытался использовать временные таблицы для хранения своих сводных данных и данных, которые нужно добавить, но вскоре обнаружил, чтопоскольку определения столбцов должны быть предопределены, мне пришлось прибегнуть к неловкому перемещению данных между временными таблицами.Кажется неоптимальным, даже если это работает, но это не так.
Логика:
BEGIN LOOP
#B = #A Join (Select value From dbo...Value Table...)
Drop Table #A
#A = #B
Drop Table #B
END
Сценарий: возвращает ошибку There is already an object named '#ResultSet' in the database.
, хотя я явно DROP TABLE #ResultSet
строка перед строкой ошибки.
--*** DECLARATION ***
USE [DB_Arc];
GO
-- ***************
-- Target Table Id
DECLARE @TagSourceID INT = 130;
-- ***************
-- Temporary Tables - DROP IF EXIST
-- #TempA
IF OBJECT_ID(N'#ResultSet') IS NOT NULL DROP TABLE #ResultSet;
CREATE TABLE dbo.#ResultSet (
DateTime DATETIME,
GroupID NVARCHAR(50)
);
-- #TempB
IF OBJECT_ID(N'#JoinSet') IS NOT NULL DROP TABLE #JoinSet;
CREATE TABLE dbo.#JoinSet (
DateTime DATETIME,
GroupID NVARCHAR(50)
);
-- Target Fields - Iterator
DECLARE field_cursor CURSOR FOR
SELECT Id, Name, RawTableName
FROM dbo.[Tag]
WHERE TagSourceId = @TagSourceID
AND Name NOT IN ('DateTime','GroupId')
AND TagTypeId NOT IN (6,7)
ORDER BY Id;
-- Local Variables
DECLARE @TagId bigint, @TagName nvarchar(250), @RawTableName nvarchar(250)
OPEN field_cursor;
-- Initial first fetch and store
FETCH NEXT FROM field_cursor
INTO @Tag, @TagName, @RawTableName;
-- Verify that the table where the values are stored is not external.
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @RawTableName)
BEGIN --IF BLOCK
-- Check @@FETCH_STATUS for any other rows to fetch
WHILE @@FETCH_STATUS = 0
-- Loop through each field/column...
BEGIN --LOOP START
-- full outer join values from rawtables to ResultSet
-- #TempB = #TempA Join (Select value From dbo...Value Table...)
DECLARE @field nvarchar(500);
SET @field =
N'SELECT a.*, b.value AS ' + QuoteName(@TagName) +
N'INTO #JoinSet
FROM #ResultSet a
FULL OUTER JOIN (
SELECT
CONVERT(datetime2, [DateTime], 1) as DateTime,
[GroupId],
[Value]
FROM dbo.' + QuoteName(@RawTableName) +
N'WHERE TagId = ' + QuoteName(@TagId) + N'AND
IsDeleted=0 ) b
ON a.DateTime = b.DateTime AND a.GroupId = b.GroupId
';
EXEC sp_executesql @field;
-- DROP TABLE #TempA
IF OBJECT_ID(N'#ResultSet') IS NOT NULL DROP TABLE #ResultSet
-- #TempA = #TempB
-- ***** ERROR BLOCK START *****
-- Returns 'There is already an object named '#ResultSet' in the database.'
SELECT *
INTO #ResultSet
FROM #JoinSet;
-- ***** ERROR BLOCK END *****
-- DROP TABLE #TempB
DROP TABLE #JoinSet;
-- Iterate values to next field
FETCH NEXT FROM field_cursor
INTO @Tag, @TagName, @RawTableName;
END --LOOP END
END --IF BLOCK END
CLOSE field_cursor;
DEALLOCATE field_cursor;
SELECT * FROM #ResultSet;
DROP TABLE #ResultSet;
GO
Я также пытался создать рекурсивную процедуру / функцию, чтобы справиться с этим, но у меня возникают проблемы с использованием курсора в качестве рекурсивного условия и таблицы переменных / tempтаблицы со статическими определениями столбцов по-прежнему остаются проблемой.
Любая помощь будет принята с благодарностью.Если у вас есть вопросы о назначении этого сценария или какие-либо общие предложения, я бы очень хотел его услышать.