How to split a string to rows in SQL without function - sql

I have the following string
Technology|faa5d304-f2d1-42c3-8d21-e87697b42bdc;Application|56b19e9a-e58a-4c79-a518-b129fb5f499f;Database|d7425391-8f8c-4aec-be04-9caf2f55584a;Mobile/BYOD|8f0f30e7-d16d-48a3-ad82-cfdd39156760;Networking|3876dbd8-8cd8-4040-9c67-0633f8477f93;Operating System|10fc2ce4-53fd-4af2-8fd9-9df66a38715f;Reporting|00307182-43f4-4bbf-9a95-cd8dbf59754a;Security|014e8d4d-4fd9-404c-8db8-13e84c9042fe;User Interface|57d65a47-6ad2-4df7-8d36-acdf3e0a3145;Web Tech|1b9e82eb-5f70-4183-9093-5
Each word in bold has to be a row. I am using the different recommendations, but I could only retrieve the first word, Technology. I need each bold words in a row. I need to approach this without function. I am using SQL Server 2012.

Try this:
DECLARE #Tabaldata TABLE ( data nvarchar(max))
INSERT INTO #Tabaldata
SELECT
'Technology|faa5d304-f2d1-42c3-8d21-e87697b42bdc;Application|56b19e9a-e58a-4c79-a518-b129fb5f499f;Database
|d7425391-8f8c-4aec-be04-9caf2f55584a;Mobile/BYOD|8f0f30e7-d16d-48a3-ad82-cfdd39156760;Networking
|3876dbd8-8cd8-4040-9c67-0633f8477f93;Operating System|10fc2ce4-53fd-4af2-8fd9-9df66a38715f;Reporting|
00307182-43f4-4bbf-9a95-cd8dbf59754a;Security|014e8d4d-4fd9-404c-8db8-13e84c9042fe;User Interface|57d65a47-6ad2-4df7-8d36-acdf3e0a3145;Web Tech|1b9e82eb-5f70-4183-9093-5'
SELECT data ActualData,
SUBSTRING(data,CHARINDEX(';' ,data)+1,LEN(data)) AS ExpectedData
FROM
(
SELECT Split.a.value('.','nvarchar(max)') data
FROM(
SELECT CAST('<S>'+REPLACE(data,'|','</S><S>')+'</S>' AS XML) data
FROM #Tabaldata
)AS A
CROSS APPLY data.nodes('S') AS Split(a)
)dt
WHERE PATINDEX('%[0-9]%',(SUBSTRING(data,CHARINDEX(';' ,data)+1,LEN(data))))=0
Demo Result :http://rextester.com/UXDT75928

Using the answer linked to by scsimon, you can use the following script to extract the bolded words in your question:
-- Test table
declare #t table (Id int identity(1,1), Col varchar(1000))
insert into #t(Col) values ('Technology|faa5d304-f2d1-42c3-8d21-e87697b42bdc;Application|56b19e9a-e58a-4c79-a518-b129fb5f499f;Database|d7425391-8f8c-4aec-be04-9caf2f55584a;Mobile/BYOD|8f0f30e7-d16d-48a3-ad82-cfdd39156760;Networking|3876dbd8-8cd8-4040-9c67-0633f8477f93;Operating System|10fc2ce4-53fd-4af2-8fd9-9df66a38715f;Reporting|00307182-43f4-4bbf-9a95-cd8dbf59754a;Security|014e8d4d-4fd9-404c-8db8-13e84c9042fe;User Interface|57d65a47-6ad2-4df7-8d36-acdf3e0a3145;Web Tech|1b9e82eb-5f70-4183-9093-5')
,('asd|a;dse|a;gggg|a')
select t.Id
,n.r.value('.', 'varchar(50)') as String
,left(n.r.value('.', 'varchar(50)'),charindex('|',n.r.value('.', 'varchar(50)'),1)-1) as Words
,substring(n.r.value('.', 'varchar(50)'),charindex('|',n.r.value('.', 'varchar(50)'),1)+1,999999) as GUIDs
from #t as t
cross apply (select cast('<r>'+replace(replace(Col,'&','&'), ';', '</r><r>')+'</r>' as xml)) as S(XMLCol)
cross apply S.XMLCol.nodes('r') as n(r)
order by t.Id
,Words;
Output:
+----+----------------------------------------------------+------------------+--------------------------------------+
| Id | String | Words | GUIDs |
+----+----------------------------------------------------+------------------+--------------------------------------+
| 1 | Application|56b19e9a-e58a-4c79-a518-b129fb5f499f | Application | 56b19e9a-e58a-4c79-a518-b129fb5f499f |
| 1 | Database|d7425391-8f8c-4aec-be04-9caf2f55584a | Database | d7425391-8f8c-4aec-be04-9caf2f55584a |
| 1 | Mobile/BYOD|8f0f30e7-d16d-48a3-ad82-cfdd39156760 | Mobile/BYOD | 8f0f30e7-d16d-48a3-ad82-cfdd39156760 |
| 1 | Networking|3876dbd8-8cd8-4040-9c67-0633f8477f93 | Networking | 3876dbd8-8cd8-4040-9c67-0633f8477f93 |
| 1 | Operating System|10fc2ce4-53fd-4af2-8fd9-9df66a387 | Operating System | 10fc2ce4-53fd-4af2-8fd9-9df66a387 |
| 1 | Reporting|00307182-43f4-4bbf-9a95-cd8dbf59754a | Reporting | 00307182-43f4-4bbf-9a95-cd8dbf59754a |
| 1 | Security|014e8d4d-4fd9-404c-8db8-13e84c9042fe | Security | 014e8d4d-4fd9-404c-8db8-13e84c9042fe |
| 1 | Technology|faa5d304-f2d1-42c3-8d21-e87697b42bdc | Technology | faa5d304-f2d1-42c3-8d21-e87697b42bdc |
| 1 | User Interface|57d65a47-6ad2-4df7-8d36-acdf3e0a314 | User Interface | 57d65a47-6ad2-4df7-8d36-acdf3e0a314 |
| 1 | Web Tech|1b9e82eb-5f70-4183-9093-5 | Web Tech | 1b9e82eb-5f70-4183-9093-5 |
| 2 | asd|a | asd | a |
| 2 | dse|a | dse | a |
| 2 | gggg|a | gggg | a |
+----+----------------------------------------------------+------------------+--------------------------------------+

Related

SQL to transpose and create rows based on column values

I have data in Postgres SQL, something like this
|KEY |Mobile1|Mobile2| M1_St_Date| M2_St_Date|M1_Exp_Date|M2_Exp_Date|
|----|-------|-------|-----------|-----------|-----------|-----------|
|1234|1234567|2234567|2014-01-01 |2015-01-01 |2019-01-01 |2020-01-01 |
|1235|1234568| |2013-01-01 | |2018-01-01 | |
|1236| |2234568| |2018-01-01 | |2023-01-01 |
I am trying to create something like below
| KEY | Type | Mobile Number|St Date |Exp Date |
| ------| --------| ----------- |-------- |----------|
| 1234 | Personal| 1234567 |2014-01-01|2019-01-01|
| 1234 | Office | 2234567 |2015-01-01|2020-01-01|
| 1235 | Personal| 1234568 |2013-01-01|2018-01-01|
| 1236 | Office | 2234568 |2018-01-01|2023-01-01|
Mobile 1 should be named as Personal & Mobile2 should be named as Office under Type Column
Appreciate any help!
SELECT
t.key,
phonetype,
phonenumber,
startdate,
enddate
FROM phone t
JOIN LATERAL (
VALUES
(
'Personal',t.Mobile1,t.M1_St_Date,t.M1_Exp_Date
),
(
'Office',t.Mobile2,t.M2_St_Date,t.M2_Exp_Date
)
) s(phonetype, phonenumber,startdate,enddate) ON TRUE
db fiddle

How to use wm_concat one a column that already exists in the query?

So... I am currently using Oracle 11.1g and I need to create a query that uses the ID and CusCODE from Table_with_value and checks Table_with_status using the ID to find active CO_status but on different CusCODE.
This is what I have so far - obviously does not work as it should unless CusCODE and ID are provided manually:
SELECT wm_concat(CoID) as active_CO_Status_for_same_ID_but_different_CusCODE
FROM Table_with_status
WHERE
CoID IN (SELECT CoID FROM Table_with_status WHERE ID = Table_with_value.ID AND CusCODE != Table_with_value.CusCODE)) AND Co_status = 'active';
Table_with_value:
|CoID | CusCODE | ID | Value |
|--------|---------|----------|----|
|354223 | 1.432 | 0784296L | 99 |
|321232 | 4.212321.22 | 0432296L | 32 |
|938421 | 3.213 | 0021321L | 93 |
Table_with_status:
|CoID | CusCODE | ID | Co_status|
|--------|--------------|----------|--------|
|354223 | 1.432 | 0784296L | active|
|354232 | 1.432 | 0784296L | inactive |
|666698 | 1.47621 | 0784296L | active |
|666700 | 1.5217 | 0784296L | active |
|938421 | 3.213 | 0021321L | active |
|938422 | 3.213 | 0021321L | active |
|938423 | 3.213 | 0021321L | active |
|321232 | 4.212321.22 | 0432296L | active |
|321232 | 4.212321.22 | 0432296L | active |
|321232 | 1.689 | 0432296L | inactive |
Expected output:
|CoID | active_CO_Status_for_same_ID_but_different_CusCODE | ID | Value |
|--------|---------|----------|----|
|354223 | 666698,666700 | 1.432 | 0784296L | 99 |
|321232 | N/A | 4.212321.22 | 0432296L | 32 |
|938421 | N/A | 3.213 | 0021321L | 93 |
Any idea on how this can be implemented ideally without any PL/SQL for loops, but it should be fine as well since the output dataset is expected < 300 IDs.
I apologize in advance for the cryptic nature in which I structured the question :) Let me know if something is not clear.
From your description and expected output, it looks like you need a left outer join, something like:
SELECT v.CoID,
wm_concat(s.CoID) as other_active_CusCODE -- active_CO_Status_for_same_ID_but_different_CusCODE
v.CusCODE,
v.ID,
v.value
FROM Table_with_value v
LEFT JOIN Table_with_status s
ON s.ID = v.ID
AND s.CusCODE != v.CusCODE
AND s.Co_status = 'active'
GROUP BY v.CoID, v.CusCODE, v.ID, v.value;
SQL Fiddle using listagg() instead of the never-supported and now-removed wm_concat(); with a couple of different approaches if the logic isn't quite what I interpreted. With your sample data they all get:
COID OTHER_ACTIVE_CUSCODE CUSCODE ID VALUE
------ -------------------- ----------- -------- -----
321232 (null) 4.212321.22 0432296L 32
354223 666698,666700 1.432 0784296L 99
938421 (null) 3.213 0021321L 93
Your code looks like it should work, assuming you are referring to the correct tables:
SELECT wm_concat(s.CoID) as active_CO_Status_for_same_ID_but_different_CusCODE
FROM Table_with_status s
WHERE s.CoID IN (SELECT v.CoID
FROM Table_with_value v
WHERE v.ID = s.ID AND
v.CusCODE <> s.CusCODE
) AND
s.Co_status = 'active';

SQL Check if the User has IN and Out

I need help getting the User which has an 'IN' and 'Out' in Column isIN. If the user has an IN and OUT do not select them in the list. I need to select the user who has only had an IN. Please I need help. Thanks in advance.
This is the table:
| Users | IsIN |
|:------------------:|:-----:|
| MHYHDC61TMJ907867 | IN |
| MHYHDC61TMJ907867 | OUT |
| MHYHDC61TMJ907922 | IN |
| MHYHDC61TMJ907922 | OUT |
| MHYHDC61TMJ907923 | IN |
| MHYHDC61TMJ907923 | OUT |
| MHYHDC61TMJ907924 | IN | - I need to get only this row
| MHYHDC61TMJ907925 | IN |
| MHYHDC61TMJ907925 | OUT |
| MHYHDC61TMJ908054 | IN | - I need to get only this row
| MHYHDC61TMJ908096 | IN | - I need to get only this row
| MHYHDC61TMJ908109 | IN | - I need to get only this row
Need to get the result like
| Users | IsIN |
|:------------------:|:-----:|
| MHYHDC61TMJ907924 | IN |
| MHYHDC61TMJ908054 | IN |
| MHYHDC61TMJ908096 | IN |
| MHYHDC61TMJ908109 | IN |
I tried using this query and sample query below but it doesn't work.
select s.[Users], s.[isIn] [dbo].[tblIO] s
where not exists (
select 1
from [dbWBS].[dbo].[tblIO] s2
where s2.[Users] = s.[Users] and s2.isIn = 'IN'
);
You can use not exists:
select s.*
from sample s
where not exists (select 1
from sample s2
where s2.user = s.user and s2.inout = 'OUT'
);
If you want only users that meet the condition (and not the full rows):
select user
from sample s
group by user
having min(inout) = max(inout) and min(inout) = 'IN';
Bearing in mind that an 'OUT' IsIn must be always preceded by an 'IN' record, you could use a query like this:
select s.Users, 'IN' as IsIn
from sample s
group by s.Users
having count(distinct s.IsIn) = 1

Sql: Unpivot with dynamic column list

I am looking to do some unpivoting in sql, converting key-values into a list of IDs. The Column from the table is dynamic and will change weekly (mayhaps even daily).
Where there maybe more KEY Columns and values possibilities.
DATABASE.PUBLIC.IMPORT_TABLE
+-----------+--------+--------+--------+
| SOURCE_ID | KEY1 | KEY2 | [KEY3] |
+-----------+--------+--------+--------+
| 0001 | TRUE | FALSE | [TBD] |
| 0002 | TRUE | FALSE | [TBD] |
| 0003 | TRUE | TRUE | [TBD] |
| 0004 | TRUE | TRUE | [TBD] |
| 0005 | FALSE | TRUE | [TBD] |
+-----------+--------+--------+--------+
To manage the possible combinations there is a table which manages the key-value pairs, and gives them an ID. This table is used to manage the Columns I am interested in. Where sometimes if there there are additional Columns added and not in this table it will be excluded.
DATABASE.PUBLIC.KEY_VALUE_TABLE
+-----------+--------+--------+
| KEY | VALUE | KV_ID |
+-----------+--------+--------+
| KEY1 | TRUE | AAA |
| KEY1 | FALSE | BBB |
| KEY2 | TRUE | CCC |
| KEY2 | FALSE | DDD |
| [KEY3] | [TRUE] | [EEE] |
+-----------+--------+--------+
Using the following query. I am able to achieve the unpivot I am looking for. However it does not take into account changes in dynamic changes for KEY_VALUE_TABLE
CREATE OR REPLACE TABLE DATABASE.PUBLIC.FINAL_TABLE AS
SELECT SOURCE_ID
,LISTAGG(DISTINCT b.KV_ID, ',') within group (order by b.KV_ID desc) AS KV_ID
FROM (
SELECT DISTINCT SOURCE_ID, KEY, VALUE from DATABASE.PUBLIC.IMPORT_TABLE
UNPIVOT(VALUE for KEY in (KEY1,KEY2))
) a
LEFT JOIN DATABASE.PUBLIC.KEY_VALUE_TABLE b
ON (a.KEY=b.KEY AND a.VALUE=b.VALUE)
GROUP BY 1,2
Where the results look like the following
DATABASE.PUBLIC.FINAL_TABLE
+-----------+--------+--------+
| SOURCE_ID | KV_ID |
+-----------+--------+--------+
| 0001 | AAA,DDD |
| 0002 | AAA,DDD |
| 0003 | AAA,CCC |
| 0004 | AAA,CCC |
| 0005 | BBB,CCC |
+-----------+--------+--------+
Is there a way to have the UNPIVOT(VALUE for KEY in (KEY1,KEY2))
to something like UNPIVOT(VALUE for KEY in (SELECT DISTINCT KEY FROM KEY_VALUE_TABLE)). Note I already tried the latter and it does not work.
SQL has an issue using SELECT within the UNPIVOT
I have also tried using UNPIVOT(VALUE for KEY in ($KEY_LIST))
Where my variable is SET KEY_LIST = '[KEY1,KEY2]'
=> SET KEY_LIST = (SELECT listagg(KEY, ',') as my_strings FROM DATABASE.PUBLIC.KEY_VALUE_TABLE)
SQL has a limit on the size of variables.
Any Advice would be appreciated.
My next step is to create a Stored Procedure or a Function. Which takes in external variables. via javascript or something similar.

casting a REAL as INT and comparing

I am casting a real to an int and a float to an int and comparing the two like this:
where
cast(a.[SUM(PAID_AMT)] as int)!=cast(b.PAID_AMT as int)
but i am still getting results where the two are equal. for example:
+-----------+-----------+------------+------------+----------+
| accn | load_dt | pmtdt | sumpaidamt | Bpaidamt |
+-----------+-----------+------------+------------+----------+
| A133312 | 6/7/2011 | 11/28/2011 | 98.39 | 98.39 |
| A445070 | 6/2/2011 | 9/22/2011 | 204.93 | 204.93 |
| A465606 | 5/19/2011 | 10/19/2011 | 560.79 | 560.79 |
| A508742 | 7/12/2011 | 10/19/2011 | 279.65 | 279.65 |
| A567730 | 5/27/2011 | 10/24/2011 | 212.76 | 212.76 |
| A617277 | 7/12/2011 | 10/12/2011 | 322.02 | 322.02 |
| A626384 | 6/16/2011 | 10/21/2011 | 415.84 | 415.84 |
| AA0000044 | 5/12/2011 | 5/23/2011 | 197.38 | 197.38 |
+-----------+-----------+------------+------------+----------+
here is the full query:
select
a.accn,
a.load_dt,
a.pmtdt,
a.[SUM(PAID_AMT)] sumpaidamt,
sum(b.paid_amt) Bpaidamt
from
[MILLENNIUM_DW_DEV].[dbo].[Millennium_Payment_Data_May2011_July2012] a
join
F_PAYOR_PAYMENTS_DAILY b
on
a.accn=b.ACCESSION_ID
and
a.final_rpt_dt=b.FINAL_REPORT_DATE
and
a.load_dt=b.LOAD_DATE
and
a.pmtdt=b.PAYMENT_DATE
where
cast(a.[SUM(PAID_AMT)] as int)!=cast(b.PAID_AMT as int)
group by
a.accn,
a.load_dt,
a.pmtdt,
a.[SUM(PAID_AMT)]
what am i doing wrong? how do i return only records that are NOT equal?
I don't see why there is an issue.
The query is returning the sum of the payments in b (sum(b.paid_amt) Bpaidamt). The where clause is comparing individual payments. This just means that there is more than one payment.
Perhaps your intention is to have a HAVING clause instead:
having cast(a.[SUM(PAID_AMT)] as int)!=cast(sum(b.PAID_AMT) as int)
You can do a round and a cast statement.
cast(round(sumpaidamt,2) as money) <> cast(round(Bpaidamt,2) as money)
Sql Fiddle showing how it would work http://sqlfiddle.com/#!3/4eb79/1