Передать динамическое имя таблицы в функцию SQL и вернуть строку с разделителями-запятыми - PullRequest
0 голосов
/ 07 марта 2011

структура mytable : id int, имя_стаблицы varchar

1, 'lookuptable1'
2, 'lookuptable2'

lookuptable1 : id int, элемент varchar

1, 'item1 from lkt1'
2, 'item2 from lkt1'

lookuptable2 : id int, item varchar

1, 'item1 from lkt2'
2, 'item2 from lkt2'

Запрос:

SELECT GetDelimitedList(lookuptablename) FROM mytable;

Ожидаемый результат:

1,2~item1 from lkt1,item2 from lkt1
1,2~item1 from lkt2,item2 from lkt2

Я пытался выяснить,способ сделать это различными способами, но просто не мог понять это.

Ответы [ 2 ]

0 голосов
/ 16 ноября 2012

Ради потомков, динамический Sql, как правило, должен быть параметризуемым (даже если в этом нет необходимости) и выполняться через sp_executesql.Полную информацию о EXEC и sp_executesql можно найти в этой (превосходной) статье:

http://www.sommarskog.se/dynamic_sql.html

Объединение предложений Эрланда по обработке ошибок с его предложениями по написанию динамических хранимых процедур приводит к шаблонуаналогично следующему:

CREATE PROCEDURE [dbo].[prc_<>]
(
    @isDebug BIT = 0
)
AS
BEGIN TRY

    SET NOCOUNT ON 
    SET XACT_ABORT ON 

    DECLARE
        @nvQry NVARCHAR(MAX)        = NULL,
        @nvParams NVARCHAR(MAX) = NULL,
        @n NVARCHAR(MAX)                = NCHAR(13) + NCHAR(10)

    -- %% Setup query here %% --

    IF @isDebug = 1
    BEGIN
        PRINT N'DECLARE ' + @n + @nvParams + @n + @n
        PRINT @nvQry
    END
    ELSE
    BEGIN
        EXEC sp_executesql @nvQry, @nvParams, 
    END 

    RETURN 0 --No Error

END TRY
BEGIN CATCH
    -- Indicate that we want to rollback entire transaction stack, 
    --  (all BEGIN TRANSACTION calls increment @@TRANCOUNT and ROLLBACK
    --      TRANSACTION returns @@TRANCOUNT to zero)
    IF @@TRANCOUNT > 0
    BEGIN
        -- Justified here: http://www.sommarskog.se/error-handling-II.html#rollbackornot
        ROLLBACK TRANSACTION
    END

    -- Augement error message and re-raise
  EXECUTE [dbo].[prc_ErrorHandler]

    -- In case this is only a statement-termination
    RETURN -1 -- Arbitrary error return value

END CATCH
GO

В случае вопроса и опираясь на ответ @ RichardTheKiwi, мы получим по общему признанию функционально эквивалентную процедуру, описанную выше, которая немного более отлаживаема:

CREATE PROCEDURE [dbo].[GetDelimitedList]
(
    @tablename NVARCHAR(128),
    @isDebug BIT = 0
)
AS
BEGIN TRY

    SET NOCOUNT ON 
    SET XACT_ABORT ON 

    DECLARE
        @nvQry NVARCHAR(MAX)        = NULL,
        @nvParams NVARCHAR(MAX) = NULL,
        @n NVARCHAR(MAX)                = NCHAR(13) + NCHAR(10)

    -- %% Setup query here %% --
    SELECT
         @nvQry = 
            N'DECLARE ' + @n +
            N'  @id NVARCHAR(MAX), ' + @n +
            N'  @item NVARCHAR(MAX) ' + @n +
            N' ' + @n +
            N'SELECT ' + @n +
            N'  @id = ISNULL(@id + '','', '''') + CONVERT(VARCHAR, [id]), ' + @n +
            N'  @item = ISNULL(@item + '','', '''') + [item] ' + @n +
            N'FROM ' + QUOTENAME(@tablename) + @n +
            N' ' + @n +
            N'SELECT @id + ''~'' + @item'

    IF @isDebug = 1
    BEGIN
        PRINT @nvQry
    END
    ELSE
    BEGIN
        EXEC sp_executesql @nvQry
    END 

    RETURN 0 --No Error

END TRY
BEGIN CATCH
    -- Indicate that we want to rollback entire transaction stack, 
    --  (all BEGIN TRANSACTION calls increment @@TRANCOUNT and ROLLBACK
    --      TRANSACTION returns @@TRANCOUNT to zero)
    IF @@TRANCOUNT > 0
    BEGIN
        -- Justified here: http://www.sommarskog.se/error-handling-II.html#rollbackornot
        ROLLBACK TRANSACTION
    END

    -- Augement error message and re-raise
  EXECUTE [dbo].[prc_ErrorHandler]

    -- In case this is only a statement-termination
    RETURN -1 -- Arbitrary error return value

END CATCH
GO
0 голосов
/ 07 марта 2011

Обходной путь. UDF не будут работать. Может быть, CLR, но не собственный SQL UDF.

Сначала создайте этот процесс, который объединит таблицу в одну строку

create proc dbo.GetDelimitedList
@tablename sysname
AS
declare @sql nvarchar(max)
set @sql = '
declare @id nvarchar(max), @item nvarchar(max)
select
    @id = isnull(@id+'','','''') + convert(varchar,id),
    @item = isnull(@item+'','','''') + item
from ' + quotename(@tablename) + '
select @id + ''~'' + @item'
exec (@sql)
GO

Затем используйте этот пакет SQL, чтобы получить вывод, эквивалентный SELECT GetDelimitedList(tablename) FROM mytable;

declare @tmp table(id int, mashed nvarchar(max))
declare @id int, @tablename sysname
-- start at first table
select top 1 @id = id, @tablename = tablename
from mytable
order by id asc
while @@ROWCOUNT > 0
begin
    -- fill our temp table
    insert @tmp (mashed) exec GetDelimitedList 'mytablelist'
    update @tmp set id = @id where id is null
    -- next table
    select top 1 @id=id, @tablename = tablename
    from mytable
    where id > @id
    order by id asc
end
SELECT * FROM @tmp;

Примеры таблиц:

create table mytable(id int, tablename varchar(100))
insert mytable values (1, 'mytablelist')
insert mytable values (3, 'mytablelist2')

create table mytablelist(id int, item varchar(100))
insert mytablelist values
(1, 'item1'),
(2, 'item2')
GO

create table mytablelist2(id int, item varchar(100))
insert mytablelist2 values
(11, 't2item1'),
(22, 't2item2')
GO
...