0

I have the following case statement as shown below:

Example:

I have the case statement:

case cola 
    when cola between '2001-01-01' and '2001-01-05' then 'G1'
    when cola between '2001-01-10' and '2001-01-15' then 'G2'
    when cola between '2001-01-20' and '2001-01-25' then 'G3'
    when cola between '2001-02-01' and '2001-02-05' then 'G4'
    when cola between '2001-02-10' and '2001-02-15' then 'G5'
    else '' 
end

Note: Now I want to create dynamic case statement because of the values dates and name passing as a parameter and it may change.

Declare @dates varchar(max) = '2001-01-01to2001-01-05,2001-01-10to2001-01-15,
                               2001-01-20to2001-01-25,2001-02-01to2001-02-05,
                               2001-02-10to2001-02-15'

Declare @names varchar(max) = 'G1,G2,G3,G4,G5'

The values in the variables may change as per the requirements, it will be dynamic. So the case statement should be dynamic without using loop.

My bad try:

DECLARE @Name varchar(max)
DECLARE @Dates varchar(max)
DECLARE @SQL varchar(max)
DECLARE @SQL1 varchar(max)

SET @Name = 'G1,G2,G3,G4,G5'
SET @dates = '2001-01-01to2001-01-05,2001-01-10to2001-01-15,
              2001-01-20to2001-01-25,2001-02-01to2001-02-05,
              2001-02-10to2001-02-15'

SELECT @SQL =  STUFF((SELECT  ' ' + Value FROM 
(
SELECT 'WHEN Cola Between '''' AND '''' THEN ''' + A.Value + '''' AS Value 
FROM 
(
    SELECT 
        Split.a.value('.', 'VARCHAR(100)') AS Value  
        FROM  
        (
        SELECT CAST ('<M>' + REPLACE(@Name, ',',
            '</M><M>') + '</M>' AS XML) AS Value 
        ) AS A 
        CROSS APPLY Value.nodes ('/M') AS Split(a)
 ) AS A
) AS B
FOR XML PATH (''), type).value('.', 'Varchar(max)'),1,1,'') + ''

SET @SQL1 = 'CASE Cola '+@SQL+' ELSE '''' END'

PRINT(@SQL1);

Stuck: But got stuck to split the @dates 2001-01-01to2001-01-05 into BETWEEN '2001-01-01' AND '2001-01-05'.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
MAK
  • 6,824
  • 25
  • 74
  • 131
  • 1
    Why would you want to do this? Seems like you are over-complicating a simple problem here. – Code Different Dec 11 '14 at 17:13
  • 1
    Just create a lookup table with the names, start dates, and end dates. Then you just have to join it to your queries. If they reset every year, make the columns `year`, `name`, `start_date`, and `end_date`. – Bacon Bits Dec 11 '14 at 17:18

1 Answers1

1

Just create a temp table (which can be inserted into dynamically) and use it in a LEFT JOIN. A LEFT JOIN (along with the COALESCE) accounts for the ELSE '' condition, but if there was no ELSE condition and all ranges were represented in the data, an INNER JOIN should be used (and no need for the COALESCE).

In order to dynamically populate the temp table from two separate variables that whose data is aligned only by position within the CSV list, and one of which is a two-dimensional array needing to be split on both comma and the string "to", I used a CTE (to make it easier to split the two-dimension @Dates variable) and a SQLCLR-based string splitter. The splitter I used is from the SQL# library (which I am the creator of but this function is in the Free version) but you can use any splitter you like (but please don't use a WHILE loop-based splitter as that is just silly).

CREATE TABLE #Cola
(
  StartDate DATETIME NOT NULL,
  EndDate DATETIME NOT NULL,
  Name NVARCHAR(50) NOT NULL
);

DECLARE @Dates VARCHAR(MAX) = '2001-01-01to2001-01-05,2001-01-10to2001-01-15,
                               2001-01-20to2001-01-25,2001-02-01to2001-02-05,
                               2001-02-10to2001-02-15';

DECLARE @Names VARCHAR(MAX) = 'G1,G2,G3,G4,G5';

-- dynamic population of temp table from two variables (@Dates being 2 dimensional)
;WITH cte AS
(
  SELECT vals.SplitNum,
         vals.SplitVal,
         CHARINDEX(N'to', vals.SplitVal) AS [WhereToSplit]
  FROM   SQL#.String_Split4k(@dates, ',', 1) vals
)
INSERT INTO #Cola (StartDate, EndDate, Name)
  SELECT CONVERT(DATETIME, SUBSTRING(cte.SplitVal, (cte.WhereToSplit - 10), 10)),
         CONVERT(DATETIME, SUBSTRING(cte.SplitVal, (cte.WhereToSplit + 2), 10)),
         names.SplitVal
  FROM cte
  INNER JOIN SQL#.String_Split4k(@names, ',', 1) names
          ON names.SplitNum = cte.SplitNum; -- keep the values aligned by position


SELECT tab.fields, COALESCE(cola.[Name], '') AS [Cola]
FROM   SchemaName.TableName tab
LEFT JOIN #Cola cola
        ON tab.cola BETWEEN cola.StartDate AND cola.EndDate
Solomon Rutzky
  • 46,688
  • 9
  • 128
  • 171
  • But I am getting `@dates` and `@name` as a comma separated string from front end like as shown above. So how can I insert those into temp table? – MAK Dec 11 '14 at 17:50
  • Error: Invalid object name 'SQL#.String_Split4k'. – MAK Dec 11 '14 at 18:22
  • @MAK Please see the note about the string splitter. SQL Server does not come with a built-in one. – Solomon Rutzky Dec 11 '14 at 18:23
  • 1
    @MAK I see in your original attempt you are doing an inline XML-based splitter. At the very least you should make that into an Inline TVF in which case it could be used in place of 'SQL#.String_Split4k' with no other changes. But it also wouldn't hurt to just go ahead and get a SQLCLR-based splitter as they are the fastest _and_ do not have encoding issues like the XML-based method does if you use a special XML character like: `<`, `"`, or `&`. – Solomon Rutzky Dec 11 '14 at 18:29
  • I did installation of built-in as you told in a note. But still getting same error. I followed all steps given in :http://www.sqlsharp.com/ – MAK Dec 11 '14 at 18:34
  • 1
    @MAK Is the current database the same as the one SQL# is installed into? If not, you need to fully qualify the name of the function as: `[dbname].SQL#.String_Split4K()`. – Solomon Rutzky Dec 11 '14 at 18:38
  • 1
    Yes! I got it. Thank you very much for being with me for such long time. – MAK Dec 11 '14 at 18:45
  • Can I get the same support of the functions in PostgreSQL 9.3 for doing the same? – MAK Jan 15 '15 at 05:39
  • @MAK If you are asking if SQL# runs in PostgreSQL, the answer is no. However, you can write your own string split function in [PL/pgSQL](http://www.postgresql.org/docs/9.3/static/plpgsql.html). – Solomon Rutzky Jan 15 '15 at 06:47
  • Hey I got stuck for the same thing in PostgreSQL. Can you please help me for this? – MAK Jan 19 '15 at 12:16
  • 1
    @MAK That is a separate question. I cannot fully help with it anyway, but you should open a new question and add a comment with that URL here. I can say that I just found a built-in split function in PostgreSQL: [regexp_split_to_table](http://www.postgresql.org/docs/9.3/static/functions-matching.html#FUNCTIONS-POSIX-REGEXP). – Solomon Rutzky Jan 19 '15 at 17:27
  • I have posted new question with more details. http://stackoverflow.com/questions/28018991/split-given-string-and-prepare-case-statement – MAK Jan 19 '15 at 17:36