Multiple Cases For Same Result Column - tsql

Have a table where one of the columns has all of the info I need for a report.
I want to substring certain portions of this column as a column in this report, but the problem is that this column has results from 3 varying character lengths.
Example:
Row1: 20180101_ABC_12
Row2: 20180102_DEFG_23
Row3: 20180103_HIJKL_45
In this particular example I want the middle portion (eg. ABC) to be a column called 'Initials', problem is I am using CASE logic for each LEN. Not sure else how to achieve this.
My sample query below. It pulls all of the possible options, but as separate columns. What would I need to do to have these 3 options pull into one column, let's call it 'Initials'?
Thanks
SELECT
FileName
, CASE WHEN LEN(FileName) = 10 THEN SUBSTRING(FileName, 10, 3) ELSE NULL END
, CASE WHEN LEN(FileName) = 11 THEN SUBSTRING(FileName, 10, 4) ELSE NULL END
, CASE WHEN LEN(FileName) = 12 THEN SUBSTRING(FileName, 10, 5) ELSE NULL END
FROM File

In Tableau, you would accomplish this using a calculated field.
Initials:
CASE LEN(FileName)
WHEN 10 THEN SUBSTRING(FileName, 10, 3)
WHEN 11 THEN SUBSTRING(FileName, 10, 4)
WHEN 12 THEN SUBSTRING(FileName, 10, 5)
END
Or maybe
SUBSTRING(FileName
,10
,CASE LEN(FileName)
WHEN 10 THEN 3
WHEN 11 THEN 4
WHEN 12 THEN 5
END
)
But barring the more technical aspect, this can be solved with math (assuming your data is either limited to the 10, 11, and 12, or that the pattern holds):
SUBSTRING(FileName
,10
,LEN(FileName)-7
)

You need 1 CASE statement covering every possible case and not 3 separate ones, because each one creates a new column:
SELECT
FileName
, CASE LEN(FileName)
WHEN 10 THEN SUBSTRING(FileName, 10, 3)
WHEN 11 THEN SUBSTRING(FileName, 10, 4)
WHEN 12 THEN SUBSTRING(FileName, 10, 5)
ELSE NULL
END AS Initials
FROM File
Another way to get everything between the 2 _:
SELECT
FileName
, substring(
left(FileName, len(FileName) - charindex('_', reverse(FileName) + '_')),
charindex('_', FileName) + 1,
len(FileName)
) AS Initials
FROM File
but from your logic I assume that the values in column FileName have the same patern:
<9 digits>_<Initials>_<2 digits>
If this is the case then you can get what you want like this:
SELECT
FileName
, substring(FileName, 10, len(FileName) - 12) AS Initials
FROM File

Related

Get Substrings From DB2 Column

I Have: AAAA/DATA1/Data2;xyx;pqr
this data
I want only:DATA1 And Data2
If this is for a specific row, maybe use SUBSTR? Something like
SELECT
SUBSTR(column, 6, 5) AS col1
, SUBSTR(column, 13, 5) AS col2
FROM table
Here is something else you can do.. Although it gets pretty complicated, and this isn't the exact answer you are looking for but it will get you started. Hope this helps:
WITH test AS (
SELECT characters
FROM ( VALUES
( 'AAAA/DATA1/Data2;xyx;pqr'
) )
AS testing(characters)
)
SELECT
SUBSTR(characters, 1, LOCATE('/', characters) - 1) AS FIRST_PART
, SUBSTR(characters, LOCATE('/', characters) + 1) AS SECOND_PART
, SUBSTR(characters, LOCATE('/', characters, LOCATE('/', characters) + 1) + 1)
AS THIRD_PART
FROM test
;
DB2 does not have a single function for this, unfortunately. Check out this answer here: How to split a string value based on a delimiter in DB2

Need to add commas to a list of numbers with regexp_replace (Postgresql)

I'm trying to write a postgres function that will sanitize a list of numbers into a list of comma-separated numbers. These numbers are being entered into an input field. I want to allow users to just enter a line of space-separated numbers (ex: 1 3 4 12) and have it change it to 1,3,4,12.
But, if they do enter it correctly (ex: 1,3,4,12 or 1, 3, 4, 12), I still want it to sanitize it to 1,3,4,12. I also have to account for things like (ex: 1, 3 4, 12).
This is what I'm currently doing:
select regexp_replace(trim(list_of_numbers), '[^0-9.] | [^,]', ',', 'g')
If I have a list like this:
select regexp_replace(trim('1, 2, 4, 14'), '[^0-9.] | [^,]', ',', 'g')
it returns : "1,2,4,14" so that's good.
But, if I have a list like this:
select regexp_replace(trim('1 2 4 14'), '[^0-9.] | [^,]', ',', 'g')
it returns : "1,,,4"
If you change your regex to [^0-9.]+ it'll replace all non-numerics (i.e. , ,, ,) with a ,.
Try it out here
I think the best option is to convert to an array using regexp_split_to_array then turn that back into a string:
The following:
with t(input) as (
values
('1 3 4 12'),
('1,3,4,12'),
('1, 3 4, 12'),
('1,3,4,12'),
('1 3 4 , 12'),
(' 1, 2 , 4 12 ')
)
select array_to_string(regexp_split_to_array(trim(input),'(\s+)|(\s*,\s*)'), ',')
from t;
returns:
array_to_string
---------------
1,3,4,12
1,3,4,12
1,3,4,12
1,3,4,12
1,3,4,12
1,3,4,12
You could split the string on any amount of whitespace or commas (,|\s)+ and join it back together using commas:
select array_to_string(regexp_split_to_array('1 2 4 14', '(,|\s)+'), ', ');

SQL Server 2012 finding text before and after delimiter and sometimes without delimiter

I have been having fun with an issue where I need to break apart a string in SQL Server 2012 and test for values it may or may not contain. The values, when present, will be separated by up to two different ; symbols.
When there is nothing, it will be blank.
When there is a single value, it will show up without the delimiter.
When there are two or more, up to 3, they will be separated by the delimiter.
As I said, if there is nothing in the record, it will be blank. Below are some example of how the data may come across:
' ',
'1',
'24',
'15;1;24',
'10;1;22',
'5;1;7',
'12;1',
'10;12',
'1;5',
'1;1;1',
'15;20;22'
I have searched the forums and found many clues, but I have not been able to come up with a total solution given all potential data values. Essentially, I would like to break it into 3 separate values.
text before the first delimiter or in the absence of the delimiter, just the text.
Text after the first delimiter and before the second in situation where there are two delimiters.
The following has worked consistently:
substring(SUBSTRING(Food_Desc, charindex(';', Food_Desc) + 1, 4), 0,
charindex(';', SUBSTRING(Food_Desc, charindex(';', Food_Desc) + 1, 4))) as [Middle]
Text after the second delimiter in the even there are two delimiters and there is a third value
The main challenge is the fact that the delimiter, when present, moves depending on the value in the table. values 1-9 make it show up as the second character in the string, values 10-24 make it show up as the 3rd, etc.
Any help would be greatly appreciated.
This is simple if you have a well written t-sql splitter function. For this solution I'm using Jeff Moden's delimitedsplit8k.
sample data and solution
DECLARE #table table (someid int identity, sometext varchar(100));
INSERT #table VALUES (' '),('1'),('24'),('15;1;24'),('10;1;22'),
('5;1;7'),('12;1'),('10;12'),('1;5'),('1;1;1'),('15;20;22');
SELECT
someid,
sometext,
ItemNumber,
Item
FROM #table
CROSS APPLY dbo.DelimitedSplit8K_LEAD(sometext, ';');
results
someid sometext ItemNumber Item
----------- ----------------- ----------- --------
1 1
2 1 1 1
3 24 1 24
4 15;1;24 1 15
4 15;1;24 2 1
4 15;1;24 3 24
5 10;1;22 1 10
5 10;1;22 2 1
5 10;1;22 3 22
6 5;1;7 1 5
6 5;1;7 2 1
6 5;1;7 3 7
7 12;1 1 12
7 12;1 2 1
8 10;12 1 10
8 10;12 2 12
9 1;5 1 1
9 1;5 2 5
10 1;1;1 1 1
10 1;1;1 2 1
10 1;1;1 3 1
11 15;20;22 1 15
11 15;20;22 2 20
11 15;20;22 3 22
Below is a modified version of a similar question How do I split a string so I can access item x?. Changing the text value for #sample to each of your possibilities listed seemed to work for me.
DECLARE #sample VARCHAR(200) = '15;20;22';
DECLARE #individual VARCHAR(20) = NULL;
WHILE LEN(#sample) > 0
BEGIN
IF PATINDEX('%;%', #sample) > 0
BEGIN
SET #individual = SUBSTRING(#sample, 0, PATINDEX('%;%', #sample));
SELECT #individual;
SET #sample = SUBSTRING(#sample, LEN(#individual + ';') + 1, LEN(#sample));
END;
ELSE
BEGIN
SET #individual = #sample;
SET #sample = NULL;
SELECT #individual;
END;
END;

TSQL - Generating Quarter output

I have a table with 3 columns X, Date and Qtr as attached.
I need to get an output as mentioned in attachment (data taken only for 8 quarters)
create table mQtr
( X varchar(5), XDate date, Qtr int);
insert into mQtr
values ('X1', '2011-11-01', 4), ('X2', '2011-10-01', 4),
('X3', '2011-09-01', 3), ('X4', '2011-08-01', 3),
('X5', '2011-07-01', 3), ('X6', '2011-06-01', 2),
('X7','2011-05-01',2), ('X8','2011-04-01',2),
('X9','2011-03-01',1), ('X10','2011-02-01',1),
('X11','2011-01-01',1), ('X12','2010-12-01',4),
('X13','2010-11-01',4), ('X14','2010-10-01',4),
('X15','2010-09-01',3), ('X16','2010-08-01',3),
('X17','2010-07-01',3), ('X18','2010-06-01',2),
('X19','2010-05-01',2), ('X20','2010-04-01',2),
('X21','2010-03-01',1), ('X22','2010-02-01',1),
('X23','2010-01-01',1), ('X24','2009-12-01',4)
What I am expecting the following result set based on Qtr value, I would like to generate sum of X values. Output should be some like this:
Qtr mOutput
----------------
1 x1+x2
2 x3+x4+x5
3 x6+x7+x8
4 x9+x10+x11
5 x12+x13+x14
6 x15+x16+x17
7 x18+x19+x20
8 x21+x22+x23
Please help me to frame the query.
Thanks,
Naveen
You can use JOIN and GROUP BY with HAVING count(*) = 3 in statement. This Link can be useful

PostgreSQL, advanced swapping

I get some help on swapping certain data in rows of same table here.
Unfortunately I can't apply those solution in practice because I represent a problem too weak so with offered solutions I can't get expected results.
For that I improve examples and make it very easy to use and for try at the same time more likely my concrete situation with hope that this post will not be treated as duplicate or offensive.
Creating a table:
DROP TABLE IF EXISTS kalksad1;
CREATE TABLE kalksad1(
kalk_id int PRIMARY KEY,
brkalk integer,
brred integer,
description text
);
INSERT INTO kalksad1 VALUES
(12, 2, 5, 'text index 12 doc 2 row 5'),
(26, 2, 1, 'text index 26 doc 2 row 1'),
(30, 2, 2, 'text index 30 doc 2 row 2'),
(32, 4, 1, 'text index 32 doc 4 row 1'),
(36, 1, 1, 'text index 36 doc 1 row 1'),
(37, 1, 2, 'text index 37 doc 1 row 2'),
(38, 5, 1, 'text index 38 doc 5 row 1'),
(39, 5, 2, 'text index 39 doc 5 row 2'),
(42, 2, 3, 'text index 42 doc 2 row 3'),
(43, 2, 4, 'text index 43 doc 2 row 4'),
(46, 3, 1, 'text index 46 doc 3 row 1'),
(47, 3, 2, 'text index 47 doc 3 row 2');
What is needed?
To make a query which will swap numbers only in column 'brred' of same 'brkalk'.
Both, 'brred' and 'brkalk' are defined externally, through program.
For example purpose we will take brkalk=2, brred=3.
That mean we should swap brred value only in rows WHEN brkalk=2.
Here are two offered solution's which may be taken as reference.
Both solutions can be useful if they would work.
First one because it can swap rows no matter of order and distance and second because it swap with only first row upper or lower what is most common need.
Problem with second solution is that I don't know what it swaps but swaps first and last row instead of row 3 and 2.
That should be repaired.
First query don't work at all in new circumstances so I would like if anyone could repair it. It can be useful for swapping rows no matter of "direction" by external arguments, say swap rows 4 and 1.
Just to clarify, when I say "swap row" I mean to swap ONLY values in 'brred' column which belongs to same 'brkalk' (in this case 2).
First query:
UPDATE kalksad1 dst
SET brred=src.brred
FROM kalksad1 src
WHERE src.brkalk='2'
AND dst.kalk_id IN(2,3)
AND src.kalk_id IN(2,3)
AND dst.kalk_id <> src.kalk_id;
Second query
WITH cte1 AS (
SELECT row_number() OVER(ORDER BY kalk_id ASC) AS row_num, kalk_id, brred
FROM kalksad1
WHERE kalk_id >= 3 ORDER BY kalk_id LIMIT 2
)
UPDATE kalksad1 AS t
SET brred = COALESCE(c2.brred, t.brred)
FROM cte1 AS c1
LEFT OUTER JOIN cte1 AS c2 ON c2.row_num <> c1.row_num
WHERE t.kalk_id = c1.kalk_id AND brkalk='2';
To view data it is best to use:
SELECT * FROM kalksad1 WHERE brkalk='2' ORDER BY brred;
I would like that someone repair upper queries to become workable according to described needs or offer new solution which may be usable for that kind of swapping.
So, thanks to Roman and wildplasser I get this...
Private Function swap_row(ByVal doc_num As Integer, ByVal src_row As Integer, ByVal dest_row As Integer) As Integer
Dim affected As Integer = 0
Dim conn As NpgsqlConnection = getConnection()
Dim t As NpgsqlTransaction = conn.BeginTransaction()
Using cmd As New NpgsqlCommand( _
"UPDATE " & myKalkSadTable & " AS dst SET brred = src.brred " & _
"FROM " & myKalkSadTable & " AS src " & _
"WHERE(src.brkalk = " & doc_num.ToString & ") " & _
"AND dst.brkalk = " & doc_num.ToString & " " & _
"AND dst.brred IN (" & src_row.ToString & "," & dest_row.ToString & ") " & _
"AND src.brred IN (" & src_row.ToString & "," & dest_row.ToString & ") " & _
"AND src.kalk_id <> dst.kalk_id", conn)
affected = CInt(cmd.ExecuteNonQuery())
cmd.Dispose()
End Using
If affected = 2 then t.Commit()
t.Dispose()
conn.Close()
conn.Dispose()
Return affected
End Function
Private Sub DataGridView2_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles DataGridView2.KeyDown
If e.Control And e.KeyCode = Keys.Left Then
swap_row(kalkbr, selected_row, selected_row - 1)
Refreshlist(kalkbr)
End If
If e.Control And e.KeyCode = Keys.Right Then
swap_row(kalkbr, selected_row, selected_row + 1)
Refreshlist(kalkbr)
End If
...etc ...
for first one you have to filter brkalk on both dst and src:
update kalksad1 as dst set
brred = src.brred
from kalksad1 as src
where
src.brkalk = 2 and dst.brkalk = 2 and
dst.brred in (2,3) and
src.brred in (2,3) and
src.kalk_id <> dst.kalk_id;
sql fiddle demo
I think second one is too complicated, I've created it when I thought that you want to swap row with exact ID and next one