Split bracket data into row in postgres - sql

I have a data in table. The questionid 201 belongs to option_3 and option_4 but when the following query is used it returns null for second output. It Should be display 201 as well.
create table test
(id integer,
questionid character varying (255),
questionanswer character varying (255));
INSERT INTO test (id,questionid,questionanswer) VALUES
(1,'[101,102,103]','[["option_11"],["KILA ALIPOKUWA ANAUMWA YEYE ALIJUWA NI AROSTO HALI YA KUKOSA KUVUTA MADAWA.."],["option_14"]]'),
(2,'[201]','[["option_3","option_4"]]');
--my query
SELECT *,
replace(unnest(string_to_array(translate(questionid, '],[ ', '","'), ',' ))::text,'"','') as questionid,
replace(unnest(string_to_array(translate(questionanswer, '],[ ', '","'), ',' ))::text,'"','') as questionanswer
from test;

Using a series of cross joins:
select t.id, t1.val, v1#>>'{}' from test t
cross join lateral (select row_number() over (order by v.value#>>'{}') r, v.value#>>'{}' val
from json_array_elements(t.questionid::json) v) t1
join lateral (select row_number() over (order by 1) r, v.value val
from json_array_elements(t.questionanswer::json) v) t2 on t1.r = t2.r
cross join lateral json_array_elements(t2.val) v1
See fiddle.

Related

How to convert this query for Spark SQL

I'm trying to convert an SQL Server query to execute it into a Notebook, but I can't figure out how to convert a "CROSS APPLY" into something that Spark can understand.
Here is my SQL Server query :
WITH Benef as (
SELECT DISTINCT
IdBeneficiaireSource
,Adress
FROM
UPExpBeneficiaryStaging
)
-------- Split Adress --------
,AdresseBenefTemp1 as (
SELECT
IdBeneficiaireSource
,REPLACE(REPLACE(Adress, char(10), '|'), char(13), '|') as AdresseV2
FROM
Benef
)
,AdresseBenefTemp2 as (
SELECT
IdBeneficiaireSource
,value as Adresse
,ROW_NUMBER() OVER(PARTITION BY IdBeneficiaireSource ORDER BY (SELECT NULL)) as LigneAdresse
FROM
AdresseBenefTemp1
CROSS APPLY string_split(AdresseV2, '|')
)
,AdresseBenefFinal as (
SELECT DISTINCT
a.IdBeneficiaireSource
,b.Adresse as Adresse_1
,c.Adresse as Adresse_2
,d.Adresse as Adresse_3
FROM
AdresseBenefTemp2 as a
LEFT JOIN AdresseBenefTemp2 as b on b.IdBeneficiaireSource = a.IdBeneficiaireSource AND b.LigneAdresse = 1
LEFT JOIN AdresseBenefTemp2 as c on c.IdBeneficiaireSource = a.IdBeneficiaireSource AND c.LigneAdresse = 2
LEFT JOIN AdresseBenefTemp2 as d on d.IdBeneficiaireSource = a.IdBeneficiaireSource AND d.LigneAdresse = 3
)
-------------------------------
SELECT
a.IdBeneficiaireSource
,Adresse_1
,Adresse_2
,Adresse_3
FROM
AdresseBenefFinal
(This query split an address field into three address fields)
When I run it into a Notebook, it says that "CROSS APPLY" is not correct.
Thanks.
Correct me if I'm wrong, but the cross apply string_split is basically a cross join for each entry in the resulting split.
In Spark you're able to use an explode for this (https://docs.databricks.com/sql/language-manual/functions/explode.html). So you should be able to add another CTE in between where you explode the splitted (https://docs.databricks.com/sql/language-manual/functions/split.html) results from AddresseV2 by '|'.

MSSQL Select a parents ID value

Having some issues with a larger MSSQL DB I am administrating.
Have some functionallity I am trying to implement in a single table.
Table looks contains such columns:
ID MailID
010-123456 12345678
010-123456/1 NULL
010-123456/2 NULL
010-123456/3 NULL
Now, what I would like to accomplish is to set each Childs MaildID to the same as its Parents MailID.
A ParentID being an ID with same value as the Child (Id ID row) before the "/" delimiter.
Also The IDs should not contins any chars, just digits (execpt for '-' and '/').
So currently I have this solution:
Declare #MyTable table(Child varchar(MAX),Parent varchar(MAX),ParentMaildId varchar(MAX))
insert into #MyTable
select ID as Child, left(ID, charindex('/', ID)-1) AS Parent, MailID as MailID
FROM [thisismy].[dbo].[table]
where ID not like '%[a-z]%' and ID like '%/%' and MailId is not NULL
select * from #MyTable
--update t1
--SET t1.MailId = t2.ParentMaildId
--FROM [thisismy].[dbo].[table] AS t1
--INNER JOIN #IDAS t2 ON t1.ID = t2.Child
--WHERE t1.ID = t2.Child and t1.MailId is NULL
When I use the select statement to get MyTable fileld up here, it only returns a low subset of all the cases that is in my DB table, why?
I would like to have stored procedure that automatically updates the Mailid of the Child to the Parent (all recuired info being in the very same table).
Is there a better way to do this?
I think you want:
select m.*, p.mailid as imputed_parent
from #mytable m cross apply
(select top (1) p.*
from #mytable p
where m.id like p.id + '/%'
order by p.id desc
) p;
You can put this in an update using a correlated subquery:
update m
set mailid = (select top (1) p.mailid
from #mytable p
where m.id like p.id + '/%'
order by p.id desc
)
from #mytable m
where m.mailid is null;
Here is a db<>fiddle.

How to convert list of comma separated Ids into their name?

I have a table that contains:
id task_ids
1 10,15
2 NULL
3 17
I have the table that has the names of this tasks:
id task_name
10 a
15 b
17 c
I want to generate the following output
id task_ids task_names
1 10,15 a,b
2 null null
3 17 c
I know this structure isn't ideal but this is legacy table which I will not change now.
Is there easy way to get the output ?
I'm using Presto but I think this can be solved with native sql
WITH data AS (
SELECT * FROM (VALUES (1, '10,15'), (2, NULL)) x(id, task_ids)
),
task AS (
SELECT * FROM (VALUES ('10', 'a'), ('15', 'b')) x(id, task_name)
)
SELECT
d.id, d.task_ids
-- array_agg will obviously capture NULL task_name comping from LEFT JOIN, so we need to filter out such results
IF(array_agg(t.task_name) IS NOT DISTINCT FROM ARRAY[NULL], NULL, array_agg(t.task_name)) task_names
FROM data d
-- split task_ids by `,`, convert into numbers, UNNEST into separate rows
LEFT JOIN UNNEST (split(d.task_ids, ',')) AS e(task_id) ON true
-- LEFT JOIN with task to pull the task name
LEFT JOIN task t ON e.task_id = t.id
-- aggregate back
GROUP BY d.id, d.task_ids;
You have a horrible data model, but you can do what you want with a bit of effort. Arrays are better than strings, so I'll just use that:
select t.id, t.task_id, array_agg(tt.task_name) as task_names
from t left join lateral
unnest(split(t.task_ids, ',')) u(task_id)
on 1=1 left join
tasks tt
on tt.task_id = u.task_id
group by t.id, t.task_id;
I don't have Presto on hand to test this. But this or some minor variant should do what you want.
EDIT:
This version might work:
select t.id, t.task_id,
(select array_agg(tt.task_name)
from unnest(split(t.task_ids, ',')) u(task_id) join
tasks tt
on tt.task_id = u.task_id
) as task_names
from t ;

SQL Server : passing company id (int) with comma in where condition [duplicate]

This question already has answers here:
How to split a comma-separated value to columns
(38 answers)
Closed 4 years ago.
I am working in SQL Server 2008. I am facing a problem in a where condition, passing multiple company ID values separated by comma (,) to use in Int company ID.
ALTER Procedure
[dbo].[SP_WorkOrderDetails] #CompanyID varchar(50)
as begin
Select
*
from
ClientContract C
left join
WorkOrder W
on
C.Id=W.ClientContractId
left join
ClientContractContacts CB
on
CB.ClientContractld=C.Id
left join
Client CL
on
CL.Id= C.Clientld
left join
Client CN
on
CN.Id= CB.Contactld
left join
BaseUnit B
on
B.Id=W.BaseUnitId
left join
users u
on
u.Staffld = W.AssignedTo
left join
LatticeERP_DFS..sv_App_Staff SPT
on
SPT.Leaderld=W.AssignedTo and
SPT.Module = 'S'
left join
Staff SS
on
SS.Id=u.StaffId --and ss.IsTeamLeader = 1
left join
Companies Comp
on
Comp.id=C.Companyld
Where
convert(nvarchar(50),isnull(C.companyID, 1)) in (replace('1,7', '''', ','))
Order By
ContractCode,
WorkOrderNo Desc
end
can you try this
IN (select cast ( STRING_SPLIT ( '1,7' , ',' ) as int ) )
or may be this
IN ( SELECT
Split.a.value('.', 'VARCHAR(100)') AS CVS
FROM
(
SELECT CAST ('<M>' + REPLACE('1,7', ',', '</M><M>') + '</M>' AS XML) AS CVS
) AS A CROSS APPLY CVS.nodes ('/M') AS Split(a) )
you can use this table-valued function:
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
GO
create FUNCTION dbo.SplitString(#str VARCHAR(4000),#seprator VARCHAR(1))
RETURNS TABLE
AS
RETURN ( WITH tokens(p,a,b) AS (SELECT 1,1,CHARINDEX(#seprator,#str)
UNION ALL SELECT p+1,b+1,CHARINDEX(#seprator,#str,b+1)
FROM tokens WHERE b>0
)
SELECT
SUBSTRING(#str,a,CASE WHEN b > 0 THEN b-a ELSE 4000 end)
AS VALUE
FROM tokens)
GO
use it like:
... where ID In(select value from dbo.SplitString('1,7,...',','))

trying to concatenate a column into a comma delimited list

i have 3 tables, 1 for products and one for categories the products are assigned to. what IM trying to do is concatenate the column called stCategoryName to a single column in a comma delimited list.
Basically I have the products table containing the primary key for each product and im trying to figure out how to concatenate all the stcategoryName column next to each product so i can have a simplified return
what im trying to get is the following.
stProductID stCategoryName
123 category1,category2,category3
SELECT
dbo.StoreItemTracking.StCategoryID,
dbo.StoreItemTracking.StProductID,
dbo.StoreItemTracking.viewOrder,
dbo.StoreCategories.StCategoryName,
dbo.Store_Products.PartNumber
FROM
dbo.StoreItemTracking
INNER JOIN dbo.StoreCategories
ON dbo.StoreItemTracking.StCategoryID = dbo.StoreCategories.StCategoryID
INNER JOIN dbo.Store_Products
ON dbo.StoreItemTracking.StProductID = dbo.Store_Products.ID
Im stuck as to how to concatenate a column where the query contains 3 tables to select from.
any help greatly appreciated
Look at using coalesce to turn category into a CSV:
See example:
DECLARE #EmployeeList varchar(100)
SELECT #EmployeeList = COALESCE(#EmployeeList + ', ', '')
+ CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1
SELECT #EmployeeList
You can also use CTE's or Subqueries. See:
http://archive.msdn.microsoft.com/SQLExamples/Wiki/View.aspx?title=createacommadelimitedlist
Another nice and easy example:
http://www.codeproject.com/Articles/21082/Concatenate-Field-Values-in-One-String-Using-CTE-i
This:
FId FName
--- ----
2 A
4 B
5 C
6 D
8 E
with:
;WITH ABC (FId, FName) AS
(
SELECT 1, CAST('' AS VARCHAR(8000))
UNION ALL
SELECT B.FId + 1, B.FName + A.FName + ', '
FROM (And the above query will return
SELECT Row_Number() OVER (ORDER BY FId) AS RN, FName FROM tblTest) A
INNER JOIN ABC B ON A.RN = B.FId
)
SELECT TOP 1 FName FROM ABC ORDER BY FId DESC
becomes:
FName
----------------------------
A, B, C, D, E,
Don't understand how your products and categories are connected but in general I do like this to create comma separated lists.
SELECT table1.Id
,Csv
FROM table1
CROSS APPLY (
-- Double select so we can have an alias for the csv column
SELECT (SELECT ',' + table2.Name
FROM table2
WHERE table2.Id = table1.Id
FOR XML PATH('')
) AS RawCsv
) AS CA1
CROSS APPLY (
-- Trim the first comma
SELECT RIGHT(RawCsv, LEN(RawCsv) - 1) AS Csv
) AS CA2