regrouper - sql server like



T-SQL: Bouclage à travers un tableau de valeurs connues (4)

Ce que je fais dans ce scénario est de créer une variable de table pour contenir les identifiants.

  Declare @Ids Table (id integer primary Key not null)
  Insert @Ids(id) values (4),(7),(12),(22),(19)

- (ou appelez une autre fonction table valorisée pour générer cette table)

Puis boucle en fonction des lignes de cette table

  Declare @Id Integer
  While exists (Select * From @Ids)
    Begin
      Select @Id = Min(id) from @Ids
      exec p_MyInnerProcedure @Id 
      Delete from @Ids Where id = @Id
    End

ou...

  Declare @Id Integer = 0 -- assuming all Ids are > 0
  While exists (Select * From @Ids
                where id > @Id)
    Begin
      Select @Id = Min(id) 
      from @Ids Where id > @Id
      exec p_MyInnerProcedure @Id 
    End

L'une ou l'autre des approches ci-dessus est beaucoup plus rapide qu'un curseur (déclaré par rapport aux tables utilisateur normales). Les variables de table ont une mauvaise réputation car lorsqu'elles ne sont pas utilisées correctement (pour les tables très larges avec un grand nombre de lignes), elles ne sont pas performantes. Mais si vous les utilisez uniquement pour contenir une valeur de clé ou un entier de 4 octets, avec un index (comme dans ce cas), ils sont extrêmement rapides.

Voici mon scénario:

Disons que j'ai une procédure stockée dans laquelle j'ai besoin d'appeler une autre procédure stockée sur un ensemble d'identifiants spécifiques; Y a-t-il un moyen de faire cela?

c'est-à-dire au lieu de devoir faire ceci:

exec p_MyInnerProcedure 4
exec p_MyInnerProcedure 7
exec p_MyInnerProcedure 12
exec p_MyInnerProcedure 22
exec p_MyInnerProcedure 19

Faire quelque chose comme ça:

*magic where I specify my list contains 4,7,12,22,19*

DECLARE my_cursor CURSOR FAST_FORWARD FOR
*magic select*

OPEN my_cursor 
FETCH NEXT FROM my_cursor INTO @MyId
WHILE @@FETCH_STATUS = 0
BEGIN

exec p_MyInnerProcedure @MyId

FETCH NEXT FROM my_cursor INTO @MyId
END

Mon objectif principal ici est simplement la maintenabilité (facile à retirer / ajouter des identifiants au fur et à mesure que l'entreprise change), la possibilité d'énumérer tous les ID sur une seule ligne ... Les performances ne devraient pas être aussi importantes


Answer #1

J'utilise habituellement l'approche suivante

DECLARE @calls TABLE (
    id INT IDENTITY(1,1)
    ,parameter INT
    )

INSERT INTO @calls
select parameter from some_table where some_condition -- here you populate your parameters

declare @i int
declare @n int
declare @myId int
select @i = min(id), @n = max(id) from @calls
while @i <= @n
begin
    select 
        @myId = parameter
    from 
        @calls
    where id = @i

        EXECUTE p_MyInnerProcedure @myId
    set @i = @i+1
end

Answer #2

utilisez une variable curseur statique et une fonction split :

declare @comma_delimited_list varchar(4000)
set @comma_delimited_list = '4,7,12,22,19'

declare @cursor cursor
set @cursor = cursor static for 
  select convert(int, Value) as Id from dbo.Split(@comma_delimited_list) a

declare @id int
open @cursor
while 1=1 begin
  fetch next from @cursor into @id
  if @@fetch_status <> 0 break
  ....do something....
end
-- not strictly necessary w/ cursor variables since they will go out of scope like a normal var
close @cursor
deallocate @cursor

Les curseurs ont une mauvaise réputation car les options par défaut lorsqu'elles sont déclarées par rapport aux tables utilisateur peuvent générer beaucoup de surcharge.

Mais dans ce cas, les frais généraux sont minimes, moins que toutes les autres méthodes ici. STATIC demande à SQL Server de matérialiser les résultats dans tempdb, puis d'itérer par-dessus. Pour les petites listes comme celle-ci, c'est la solution optimale.


Answer #3
CREATE TABLE #ListOfIDs (IDValue INT)

DECLARE @IDs VARCHAR(50), @ID VARCHAR(5)
SET @IDs = @OriginalListOfIDs + ','

WHILE LEN(@IDs) > 1
BEGIN
SET @ID = SUBSTRING(@IDs, 0, CHARINDEX(',', @IDs));
INSERT INTO #ListOfIDs (IDValue) VALUES(@ID);
SET @IDs = REPLACE(',' + @IDs, ',' + @ID + ',', '')
END

SELECT * 
FROM #ListOfIDs




tsql