2010-06-02 6 views
1

Je suis nouveau avec T-SQL. Alors, s'il vous plaît aidez-moi à écrire le sql.SQL pour retourner une table basée sur l'entrée de chaîne

J'ai la table Prix (colonne Code est la colonne primaire):

Code Value 
A1  234 
A2  525 
A3  566 

Je saisiront une chaîne et la nécessité sql pour retourner une table.

Ex1: entrée 'A2' -> retour:

Code Value 
A2  525 

Ex2: entrée 'A1 A3' -> retour:

Code Value 
A1  234 
A3  566 

Ex3: entrée 'A1 A3 A1' -> retour :

Code Value 
A1  234 
A3  566 

Ex4: entrée 'A1 A4' -> retour:

Code Value 
A1  234 

S'il vous plaît aidez-moi. J'utilise SQL Server 2005. Tks.

+0

question voulez-vous des déclarations distinctes pour chaque ou une procédure stockée qui vous permettra de retourner tous ces scénarios? –

+0

Je dois écrire une procédure stockée qui nécessite un paramètre de chaîne et une table de sortie. Merci. –

Répondre

2
SELECT [Price].Code, [Price].Value FROM [Price] WHERE [Price].Code IN ('A1', 'A2'); 

Il est très efficace, mais il a deux limites:

  • Vous ne pouvez pas utiliser les paramètres SQL réguliers dans une clause IN, de sorte que vous aurez l'ajouter à votre chaîne SQL automatiquement, qui, dans certains cas, pourrait ouvrir des injections SQL.

  • Ce n'est pas exactement le format d'entrée que vous avez demandé: au lieu de A2 A2, c'est 'A1', 'A2'.

Bonne chance quand même!

EDIT: Si vous voulez vraiment utiliser le format A1 A2, vous ne pouvez pas utiliser IN et vous auriez à diviser la chaîne et vérifier si elle contient le [Price].Code courant. Notez simplement que ce sera beaucoup moins efficace que mon premier exemple.

T-SQL ne prend pas en charge Split par défaut, vous devrez l'ajouter manuellement:

CREATE FUNCTION [dbo].[Split] 
( 
    @RowData NVARCHAR(MAX), 
    @Delimeter NVARCHAR(MAX) 
) 
RETURNS @RtnValue TABLE 
(
    ID INT IDENTITY(1,1), 
    Data NVARCHAR(MAX) 
) 
AS 
BEGIN 
    DECLARE @Iterator INT 
    SET @Iterator = 1 

    DECLARE @FoundIndex INT 
    SET @FoundIndex = CHARINDEX(@Delimeter,@RowData) 

    WHILE (@FoundIndex>0) 
    BEGIN 
     INSERT INTO @RtnValue (data) 
     SELECT 
      Data = LTRIM(RTRIM(SUBSTRING(@RowData, 1, @FoundIndex - 1))) 

     SET @RowData = SUBSTRING(@RowData, 
       @FoundIndex + DATALENGTH(@Delimeter)/2, 
       LEN(@RowData)) 

     SET @Iterator = @Iterator + 1 
     SET @FoundIndex = CHARINDEX(@Delimeter, @RowData) 
    END 

    INSERT INTO @RtnValue (Data) 
    SELECT Data = LTRIM(RTRIM(@RowData)) 

    RETURN 
END 

Et puis, vous pouvez faire quelque chose comme ceci:

SELECT [Price].Code, [Price].Value FROM [Price] 
JOIN Split(@Codes, ' ') AS [Code] 
ON [Code].Data = [Price].Code 

Here's the source for the Split function .

+0

Mais comment diviser la chaîne de 'A1 A2' à 'A1' et 'A2'. Ma procédure de magasin nécessite un paramètre de chaîne. –

+0

Voir ma modification s'il vous plaît. –

0

Comme l'a mentionné Alon, vous avez besoin d'une fonction ou d'une requête pour diviser les valeurs en lignes dans une table. Une autre façon de le faire est avec une table de nombres qui peut être statique ou créé dans le cadre d'une expression de table commune:

Declare @Alist varchar(50); 
Declare @Delimiter char(1); 
Declare @DelimiterLength int; 

Set @Delimiter = ' '; 
Set @DelimiterLength = DataLength(@Delimiter); 
Set @Alist = 'A1 A2 A3'; 
Set @Alist = @Delimiter + @Alist + @Delimiter; 

With Numbers As 
    (
    Select Row_Number() Over (Order By C1.object_id) As Value 
    From sys.columns As C1 
     Cross Join sys.columns As C2 
    ) 
Select CharIndex(@Delimiter, @Alist, N.Value) + @DelimiterLength As Position    
    , Substring (
       @Alist 
       , CharIndex(@Delimiter, @Alist, N.Value) + @DelimiterLength   
       , CharIndex(@Delimiter, @Alist, N.Value + 1)        
        - (CharIndex(@Delimiter, @Alist, N.Value) + @DelimiterLength) 
       ) As Value 
From Numbers As N 
Where N.Value Between 1 And (Len(@Alist) - 1) 
    And Substring(@Alist, N.Value, @DelimiterLength) = @Delimiter 
Order By N.Value 

Ici le délimiteur espace présente un petit problème. La fonction Len ignore les espaces dans sa détermination, j'ai donc utilisé la fonction DataLength et également m'assurer que @Delimiter a été déclaré comme varchar au lieu d'un nvarchar.DataLength renverra le nombre d'octets dans la chaîne qui sera deux fois le nombre de caractères en général pour un nvarchar.

Le nombre CTE (ou il pourrait être une table statique) est juste une liste statique d'entiers séquentiels qui est très utile pour des situations comme celle-ci.

Ce type d'approche peut également être incorporée dans une requête générale où vous analysez chaque ligne dans une autre table comme ceci:

With Numbers As 
    (
    Select Row_Number() Over (Order By C1.object_id) As Value 
    From sys.columns As C1 
     Cross Join sys.columns As C2 
    ) 
Select CharIndex(@Delimiter, A.List, N.Value) + @DelimiterLength    
    , Substring (
       A.List 
       , CharIndex(@Delimiter, A.List, N.Value) + @DelimiterLength   
       , CharIndex(@Delimiter, A.List, N.Value + 1)        
        - (CharIndex(@Delimiter, A.List, N.Value) + @DelimiterLength) 
       ) 
From Numbers As N 
    Cross Join (Select A1.List From SomeTable) As A 
Where N.Value Between 1 And (Len(A.List) - 1) 
    And Substring(A.List, N.Value, @DelimiterLength) = @Delimiter 
Order By N.Value 
Questions connexes