0

I'm trying to write a query that will have a column show a specific value depending on another comma delimited column. The codes are meant to denote Regular time/overtime/doubletime/ etc. and they come from the previously mentioned comma delimited column. In the original view, there are columns for each of the different hours accrued separately. For the purposes of this, we can say A = regular time, B = doubletime, C = overtime. However, we have many codes that can represent the same type of time.

What my original view looks like:

Employee_FullName EmpID Code Regular Time Double Time Overtime
John Doe 123 A,B 7 2 0
Jane Doe 234 B 4 0 1

What my query outputs:

Employee_FullName EmpID Code Hours
John Doe 123 A, B 10
John Doe 123 A, B 5
Jane Doe 234 B 5

What I want the output to look like:

Employee_FullName EmpID Code Hours
John Doe 123 A 10
John Doe 123 B 5
Jane Doe 234 B 5

It looks the way it does in the first table because currently it's only pulling from the regular time column. I've tried using a case switch to have it look for a specific code and then pull the number, but I get a variety of errors no matter how I write it. Here's what my query looks like:

SELECT [Employee_FullName],
    SUBSTRING(col, 1, CHARINDEX(' ', col + ' ' ) -1)'Code',
    hrsValue
FROM
    (
    SELECT [Employee_FullName], col, hrsValue
    FROM myTable
    CROSS APPLY
    (
        VALUES ([Code],[RegularHours])
    ) C (COL, hrsValue)
) SRC

Any advice on how to fix it or perspective on what to use is appreciated!

Edit: I cannot change the comma delimited data, it is provided that way. I think a case within a cross apply will solve it but I honestly don't know.

Edit 2: I will be using a unique EmployeeID to identify them. In this case yes A is regular time, B is double time, C is overtime. The complication is that there are a variety of different codes and multiple refer to each type of time. There is never a case where A would refer to regular time for one employee and double time for another, etc. I am on SQL Server 2017. Thank you all for your time!

  • 2
    There is no case in you attempt? Show show us the attempt with the case. – Dale K Oct 18 '21 at 23:26
  • I don't know where to start with putting a case in it. I tried creating a temp variable to hold a value that would then represent the code, but then I would have to find a way for it to read the comma delimited column anyway. Is that the best way to go about it? – Gabriella C. Oct 18 '21 at 23:27
  • You can replace a column name with a case expression inside your `VALUES` statement. – Dale K Oct 18 '21 at 23:34
  • And if you want to make it really easy for people to assist, provide the DDL+DML for your sample data. – Dale K Oct 18 '21 at 23:35
  • Why are you storing your data as comma delimited anyway? Thats just asking for trouble. Store it properly and save yourself the pain. If you have to do it, that question has been asked 100's of times on this site already. Your question title is misleading, rather than telling us the problem you are trying to solve, you're telling us what you think the solution will be - which is never a good way to write a question. – Dale K Oct 18 '21 at 23:37
  • Unfortunately I have no control over how that particular data is stored, it's given to me that way and I have to use it as it's provided. I will try rewriting my question. – Gabriella C. Oct 18 '21 at 23:41
  • https://stackoverflow.com/questions/10581772/how-to-split-a-comma-separated-value-to-columns – Dale K Oct 19 '21 at 00:08
  • 1
    What version of SQL Server? Also can you provide some sample data / desired results for overtime? And what happens if you have two John Does? Are you really using FullName to identify an employee? – Aaron Bertrand Oct 19 '21 at 01:31
  • Can you better define "I've tried using a case switch to have it look for a specific code and then pull the number" - does A refer to regular, B to double time, and C to overtime? Or is there a lookup table we don't know about yet that somehow maps A to regular time for John but B to double time for John and regular time for Jane? – Aaron Bertrand Oct 19 '21 at 01:49
  • Also can you please change your sample data so that all three time values are distinct? Currently with two values both having `5` it makes the desired result ambiguous - does John have a 5 for code B because they had 5 in Double Time, or are the names swapped? What are the desired results if, say, Jane Doe's regular time is 7, and John Doe's double time is 14? – Aaron Bertrand Oct 19 '21 at 04:11
  • I hadn't really thought through what to use as the primary key so I understand the confusion on using FullName. I will be using a unique EmployeeID to identify them. In this case yes A is regular time, B is double time, C is overtime. The complication is that there are a variety of different codes and multiple refer to each type of time. There is never a case where A would refer to regular time for one employee and double time for another, etc. I am SQL Server 2017. I'm going to make some changes to my question to address all of this. Thank you all for your time! – Gabriella C. Oct 19 '21 at 15:09

3 Answers3

2

If you are on SQL Server 2016 or better, you can use OPENJSON() to split up the code values instead of cumbersome string operations:

SELECT t.Employee_FullName,
       Code = LTRIM(j.value),
       Hours = MAX(CASE j.[key] 
                   WHEN 0 THEN RegularTime
                   WHEN 1 THEN DoubleTime
                   WHEN 2 THEN Overtime END)
  FROM dbo.MyTable AS t
  CROSS APPLY OPENJSON('["' + REPLACE(t.Code,',','","') + '"]') AS j
  GROUP BY t.Employee_FullName, LTRIM(j.value);
Aaron Bertrand
  • 272,866
  • 37
  • 466
  • 490
  • This solution worked very elegantly, and did exactly what I wanted it to do. Thank you very much for your assistance! – Gabriella C. Oct 19 '21 at 15:41
1

You can use the following code to split up the values

  • Note how NULLIF nulls out the CHARINDEX if it returns 0
  • The second half of the second APPLY is conditional on that null
SELECT
  t.[Employee_FullName],
  Code = TRIM(v2.Code),
  v2.Hours
FROM myTable t
CROSS APPLY (VALUES( NULLIF(CHARINDEX(',', t.Code), 0) )) v1(comma)
CROSS APPLY (
    SELECT Code = ISNULL(LEFT(t.Code, v1.comma - 1), t.Code), Hours = t.RegularTime
    UNION ALL
    SELECT SUBSTRING(t.Code, v1.comma + 1, LEN(t.Code)), t.DoubleTime
      WHERE v1.comma IS NOT NULL
) v2;

db<>fiddle

Charlieface
  • 52,284
  • 6
  • 19
  • 43
0

You can go for CROSS APPLY based approach as given below.

Thanks to @Chalieface for the insert script.

CREATE TABLE mytable (
  "Employee_FullName" VARCHAR(8),
  "Code" VARCHAR(3),
  "RegularTime" INTEGER,
  "DoubleTime" INTEGER,
  "Overtime" INTEGER
);

INSERT INTO mytable
  ("Employee_FullName", "Code", "RegularTime", "DoubleTime", "Overtime")
VALUES
  ('John Doe', 'A,B', '10', '5', '0'),
  ('Jane Doe', 'B', '5', '0', '0');

  SELECT
  t.[Employee_FullName],
  c.Code,
  CASE WHEN c.code = 'A' THEN t.RegularTime
       WHEN c.code = 'B' THEN t.DoubleTime
       WHEN c.code = 'C' THEN t.Overtime
       END AS Hours
  FROM myTable t
CROSS APPLY (select value from string_split(t.code,',')
) c(code)
Employee_FullName Code Hours
John Doe A 10
John Doe B 5
Jane Doe B 0
Venkataraman R
  • 12,181
  • 2
  • 31
  • 58
  • It's not quite the desired results (you have only used `RegularTime` but _I think_ the OP wants the second row there to have the value from `DoubleTime`): https://dbfiddle.uk/?rdbms=sqlserver_2016&fiddle=babac963015ffa73dde138e833468df8 – Aaron Bertrand Oct 19 '21 at 04:10
  • @AaronBertrand, sorry. I have corrected the answer. Thanks for your check. Btw, I am fan of your SQL Server posts. I especially like your TSQL Bad habits to kick. Thanks for your service to SQL Server community. – Venkataraman R Oct 19 '21 at 04:36
  • Thanks! But Jane Doe should have 5, not 0, at least according to the question - I'm not quite sure that A or B means anything, it's just the position in the list that maps to which hours to pull. But I still think there might be something wrong with the sample data / desired results. – Aaron Bertrand Oct 19 '21 at 10:57
  • @AaronBertrand, yes. agree with you. there is confusion in the sample data and expected output. – Venkataraman R Oct 19 '21 at 11:06