How to parse a string and get the value after "=" character - mysql

So I have string that should contains "Object.Name" once in a row , if I see it ,I have to get the value after "=" character. If doesn't match it anywhere in the string i should move hardcoded value.
Here is example of the string:
Object.Name=ASDD||Product.Name=DSA
Product.Name=QWE||Object.Name=WSXS
Storage.Name=12345||Object.Name=WERR||Product.Name=QAZ
I know that I should use case for that but doesn't know how to proceed the string
case
when (match the string ) then (value after the "=")
else (hardcoded value)
end

In Oracle, you can use:
SELECT value,
CASE
WHEN start_pos = 0
THEN NULL
ELSE SUBSTR(
'||' || value || '||',
start_pos + LENGTH('||Object.Name='),
end_pos - start_pos - LENGTH('||Object.Name=')
)
END AS object_name
FROM (
SELECT value,
INSTR(
'||' || value || '||',
'||Object.Name='
) AS start_pos,
INSTR(
'||' || value || '||',
'||',
INSTR('||' || value || '||', '||Object.Name=')+LENGTH('||Object.Name=')
) AS end_pos
FROM table_name
)
Which, for the sample data:
CREATE TABLE table_name (value) AS
SELECT 'Object.Name=ASDD||Product.Name=DSA' FROM DUAL UNION ALL
SELECT 'Product.Name=QWE||Object.Name=WSXS' FROM DUAL UNION ALL
SELECT 'Storage.Name=12345||Object.Name=WERR||Product.Name=QAZ' FROM DUAL;
Outputs:
VALUE
OBJECT_NAME
Object.Name=ASDD||Product.Name=DSA
ASDD
Product.Name=QWE||Object.Name=WSXS
WSXS
Storage.Name=12345||Object.Name=WERR||Product.Name=QAZ
WERR
db<>fiddle here
Since you changed the tags, in MySQL:
SELECT value,
CASE
WHEN start_pos = 0
THEN NULL
ELSE SUBSTRING(
CONCAT('||', value, '||'),
start_pos + LENGTH('||Object.Name='),
end_pos - start_pos - LENGTH('||Object.Name=')
)
END AS object_name
FROM (
SELECT value,
LOCATE(
'||Object.Name=',
CONCAT('||', value, '||')
) AS start_pos,
LOCATE(
'||',
CONCAT('||', value, '||'),
LOCATE('||Object.Name=', CONCAT('||', value, '||'))
+ LENGTH('||Object.Name=')
) AS end_pos
FROM table_name
) t
db<>fiddle here

Related

MySQL: Updating multiple columns using if else

I need help to set a mySQL update query for my little project like below:
UPDATE TABLE
IF SUBSTRING_INDEX(REFERENCE, '_', -1)= 'A' THEN
{
TYPE = 1
COLOR = 'BLUE'
}
ELSEIF SUBSTRING_INDEX(REFERENCE, '_', -1)= 'B' THEN
{
TYPE = 2
COLOR = 'RED'
},
ID = SUBSTRING_INDEX(REFERENCE, '_', 1)
WHERE REFERENCE IS NOT NULL
In my table, there is a column REFERENCE which contains varchar like
A_1, A_2, A_10
B_1, B_4, B_12
etc...
where the character before the symbol '_' determines certain values for other columns like stated above.
I am still fairly new to mySQL, so appreciates any help!
You can use case expressions:
UPDATE TABLE
SET TYPE = (CASE WHEN SUBSTRING_INDEX(REFERENCE, '_', -1) = 'A'
THEN 1
WHEN SUBSTRING_INDEX(REFERENCE, '_', -1) = 'B'
THEN 2
ELSE TYPE
END),
COLOR = (CASE WHEN SUBSTRING_INDEX(REFERENCE, '_', -1) = 'A'
THEN 'BLUE'
WHEN SUBSTRING_INDEX(REFERENCE, '_', -1) = 'B'
THEN 'RED'
ELSE COLOR
END),
ID = SUBSTRING_INDEX(REFERENCE, '_', 1)
WHERE REFERENCE IS NOT NULL;

Split comma separated values in a particular comma postion using SQL or SSRS report

I have a field in SSRS that is concatenated values like
1234,1456,3456,7890,3457,3245,4345
I need to break/split after 8th comma or in a particular position in next row like:
1234,1456,3456,
7890,3457,3245,
4345
Here values are dynamic but, we have to split/break at every 8th or particular comma
In your example text, all the values have four characters. If that is the case, a simple recursive CTE does what you want:
with cte as (
select convert(varchar(max), NULL) as val, convert(varchar(max), field) as rest, 0 as lev
from t
union all
select left(rest, 15) as val, stuff(rest, 1, 15, '') as rest, lev+1
from cte
where rest <> ''
)
select val
from cte
where lev > 0;
Here is a db<>fiddle.
Once you've grabbed a copy of DelimitedSplit8K_LEAD (as STRING_SPLIT has no concept of ordinal positions) you can split the string and then "re-aggregate" it.
Using SQL Server 2017+:
DECLARE #YourString varchar(8000) = '1234,1456,3456,7890,3457,3245,4345';
WITH Split AS(
SELECT DS.Item,
DS.ItemNumber,
(DS.ItemNumber - 1) / 3 AS Grp
FROM dbo.DelimitedSplit8K_LEAD(#YourString,',') DS)
SELECT STRING_AGG(S.Item,',') WITHIN GROUP (ORDER BY S.ItemNumber ASC) AS NewString
FROM Split S
GROUP BY S.Grp;
SQL Server 2016-:
DECLARE #YourString varchar(8000) = '1234,1456,3456,7890,3457,3245,4345';
WITH Split AS(
SELECT DS.Item,
DS.ItemNumber,
(DS.ItemNumber - 1) / 3 AS Grp
FROM dbo.DelimitedSplit8K_LEAD(#YourString,',') DS)
SELECT STUFF((SELECT ',' + sq.Item
FROM Split sq
WHERE sq.Grp = S.Grp
ORDER BY sq.ItemNumber
FOR XML PATH(''),TYPE).value('.','varchar(8000)'),1,1,'') AS MewString
FROM Split S
GROUP BY S.Grp;
If you use SQL Server 2016+, you may use an approach, based on JSON. Just transform the input text into a valid JSON array and parse this array with OPENJSON():
Example with text:
Statement:
DECLARE #json nvarchar(max) = N'1234,1456,3456,7890,3457,3245,4345'
SELECT CONCAT(
MAX(CASE WHEN CONVERT(int, [key]) % 3 = 0 THEN [value] END),
MAX(CASE WHEN CONVERT(int, [key]) % 3 = 1 THEN [value] END),
MAX(CASE WHEN CONVERT(int, [key]) % 3 = 2 THEN [value] END)
) AS OutputText
FROM OPENJSON(CONCAT(N'["', REPLACE(#json, N',', N',","'), N'"]'))
GROUP BY (CONVERT(int, [key]) / 3)
Result:
---------------
OutputText
---------------
1234,1456,3456,
7890,3457,3245,
4345
Example with table:
Table:
CREATE TABLE Data (TextData nvarchar(max))
INSERT INTO Data (TextData)
VALUES (N'1234,1456,3456,7890,3457,3245,4345')
Statement:
SELECT d.TextData, c.OutputData
FROM Data d
CROSS APPLY (
SELECT CONCAT(
MAX(CASE WHEN CONVERT(int, [key]) % 3 = 0 THEN [value] END),
MAX(CASE WHEN CONVERT(int, [key]) % 3 = 1 THEN [value] END),
MAX(CASE WHEN CONVERT(int, [key]) % 3 = 2 THEN [value] END)
) AS OutputData
FROM OPENJSON(CONCAT(N'["', REPLACE(d.TextData, N',', N',","'), N'"]'))
GROUP BY (CONVERT(int, [key]) / 3)
) c
Result:
---------------------------------------------------
TextData OutputData
---------------------------------------------------
1234,1456,3456,7890,3457,3245,4345 1234,1456,3456,
1234,1456,3456,7890,3457,3245,4345 7890,3457,3245,
1234,1456,3456,7890,3457,3245,4345 4345

Aliasing a CASE statement

I would need your help to fix a problem I'm facing.. I'm using a CASE function and aliasing its result by adding "AS 'RESULT'" after its "END".
Event though the query seems to run, I'm still getting the following warnings through phpmyadmin :
Unrecognized keyword (near AS)
Unexpected token (near 'RESULT')
I have no idea on why I'm getting this...I would appreciate your help to highlight my mistake ;-)
SELECT
app_fd_List_of_components.c_component,
app_fd_List_of_orders.c_package,
app_fd_List_of_orders.c_status,
app_fd_List_of_orders.dateCreated,
app_fd_List_of_orders.c_orderId,
app_fd_List_of_orders.Id,
temptablename.datetime AS Int_Date,
temptablename2.datetime AS Prdw3_Date,
#counterStatus := IF(
app_fd_List_of_orders.c_status <> 'Deployment completed',
IF(
temptablename.datetime IS NOT NULL,
'Counting',
'Initializing'
),
'Complete'
) AS 'Counter_status',
#counter := IF(
app_fd_List_of_orders.c_status <> 'Deployment completed',
IF(
temptablename.datetime IS NOT NULL,
(
35 - DATEDIFF(
CURRENT_DATE(), temptablename.datetime)
),
'n/a'
),
DATEDIFF(
temptablename2.datetime,
temptablename.datetime
)
) AS 'Counter',
CASE (WHEN(
(#counterStatus = 'Counting') AND(#counter < 0)
) THEN "black" WHEN(
(#counterStatus = 'Counting') AND(#counter > 5)
) THEN "green" WHEN(
(#counterStatus = 'Counting') AND(-1 < #counter < 5)
) THEN "orange" WHEN(
(#counterStatus = 'Complete') AND(#counter > 35)
) THEN "black" WHEN(
(#counterStatus = 'Complete') AND(#counter < 35)
) THEN "green" ELSE "n/a")
END AS 'RESULT'
FROM
app_fd_List_of_orders
JOIN app_fd_List_of_components ON
app_fd_List_of_orders.c_component = app_fd_list_of_components.id
LEFT JOIN(
SELECT app_form_data_audit_trail.datetime,
app_form_data_audit_trail.data
FROM
app_form_data_audit_trail
WHERE
SUBSTRING_INDEX(
SUBSTRING_INDEX(
app_form_data_audit_trail.data,
'"opdetails":"',
-1
),
'"',
1
) = 'int'
) AS temptablename
ON
app_fd_list_of_orders.c_orderid = SUBSTRING_INDEX(
SUBSTRING_INDEX(
temptablename.data,
'"orderId":"',
-1
),
'"',
1
)
LEFT JOIN(
SELECT app_form_data_audit_trail.datetime,
app_form_data_audit_trail.data
FROM
app_form_data_audit_trail
WHERE
SUBSTRING_INDEX(
SUBSTRING_INDEX(
app_form_data_audit_trail.data,
'"opdetails":"',
-1
),
'"',
1
) = 'prdw3'
) AS temptablename2
ON
app_fd_list_of_orders.c_orderid = SUBSTRING_INDEX(
SUBSTRING_INDEX(
temptablename2.data,
'"orderId":"',
-1
),
'"',
1
)
Have you tried removing the parentheses around the CASE statement?
CASE
WHEN #counterStatus = 'Counting' AND #counter < 0 THEN "black"
WHEN #counterStatus = 'Counting' AND #counter > 5 THEN "green"
WHEN #counterStatus = 'Counting' AND -1 < #counter < 5 THEN "orange"
WHEN #counterStatus = 'Complete' AND #counter > 35 THEN "black"
WHEN #counterStatus = 'Complete' AND #counter < 35 THEN "green"
ELSE "n/a"
END AS 'RESULT'
EDIT: I'm also not sure this is possible:
WHEN #counterStatus = 'Counting' AND -1 < #counter < 5 THEN "orange"
It may need to be written as:
WHEN #counterStatus = 'Counting' AND -1 < #counter AND #counter < 5 THEN "orange"

Flattening a Table in prep for Json

Maybe it's that I'm tired but this is escaping me.
Let's say that I want to flatten this table:
a_id a_val b_id b_val c_id c_val d_id d_val
1 a 10 b 100 c 1000 f
1 a 20 d 200 g null null
2 e 30 h 300 i null null
2 j 40 k null null null null
3 l null null null null null null
Into this query result:
id mystring
1, (1:a,10:b,100:c,1000:f),(1:a,20:d,200:g)
2, (2:e,30:h,300:i),(2:j,40:k)
3, (3:l)
The table only renders four levels deep (a, b, c, d) so no dynamic sql issue.
Now I'd usually just use GROUP_CONCAT(CONCAT(...)) but that won't work with the Nulls present. And maybe using coalesce somehow will solve this but... I feel pretty stupid at the moment... and I can't figure it out.
Unfortunately I can't use mysql json services on this installation so I need to construct the data. thanks.
The solution here will probably just be a combination of clever concatenation and IFNULL calls. My shot in the dark:
SELECT a_id, GROUP_CONCAT(CONCAT('(',
a_id, ':', a_value, ',',
IFNULL(b_id, ''), IF(b_id IS NOT NULL, ':', ''), IFNULL(b_val, ''),
...repeat for c and d
')'
) SEPARATOR ',')
FROM table
GROUP BY a_id;
select a_id as id,
group_concat(concat(
case isnull(a_id) when true then '' else '(' end,
coalesce(a_id, ''),
case isnull(a_id) when true then '' else ':' end,
coalesce(a_val, ''),
case isnull(b_id) when true then '' else ',' end,
coalesce(b_id, ''),
case isnull(b_id) when true then '' else ':' end,
coalesce(b_val, ''),
case isnull(c_id) when true then '' else ',' end,
coalesce(c_id, ''),
case isnull(c_id) when true then '' else ':' end,
coalesce(c_val, ''),
case isnull(d_id) when true then '' else ',' end,
coalesce(d_id, ''),
case isnull(d_id) when true then '' else ':' end,
coalesce(d_val,''),
case isnull(a_id) when true then '' else ')' end
) separator ',')
from table
group by a_id;

SQL - Extract a numeric part of a variable length string

Here is an example:
[U_TipTon]=118.7->59.35;[U_Haulge]=428.28->214.14
I need to extract just 118.7->59.35 as Tipton, and 428.28->214.14 in another column as U_Haulage.
The length of the string is variable as well as the posision os my pattern word.
I am trying with Patindex but I cannot find the way.
In MySQL there's SUBSTRING_INDEX, which extracts a substring based on a delimiter:
select
substring_index(substring_index(x, '[U_TipTon]=', -1), ';', 1) as TipTon
,substring_index(substring_index(x, '[U_Haulge]=', -1), ';', 1) as Haulge
from
(
select '[U_TipTon]=118.7->59.35;[U_Haulge]=428.28->214.14' as x
) as dt
Edit:
In MS SQL Server it's more complicated:
select
substring(xHaulge, 1, charindex(';', xHaulge + ';')-1) as Haulge,
substring(xTipTon, 1, charindex(';', xTipTon + ';')-1) as TipTon
from
(
select
case when charindex('[U_Haulge]=', x) > 0
then substring(x, charindex('[U_Haulge]=', x) + len('[U_Haulge]='), 8000)
else ''
end as xHaulge,
case when charindex('[U_TipTon]=', x) > 0
then substring(x, charindex('[U_TipTon]=', x) + len('[U_TipTon]='), 8000)
else ''
end as xTipTon
from
(
select '[U_TipTon]=118.7->59.35;[U_Haulge]=428.28->214.14' as x
) as dt
) as dt
The solution was:
case
when charindex('Haulge',t.xField) > 0 then
substring( t.xField , charindex('Haulge',t.xField) + 8,case when charindex(';',substring( t.xField , charindex('Haulge',t.xField) + 8,LEN(t.xField))) = 0
then LEN(t.xField)
else charindex(';',substring( t.xField , charindex('Haulge',t.xField) + 8,LEN(t.xField)))-1 end )
else '-' end [Haul Price]
,case
when charindex('Tipton',t.xField) > 0 then
substring( t.xField , charindex('TipTon',t.xField) + 8,case when charindex(';',substring( t.xField , charindex('Tipton',t.xField) + 8,LEN(t.xField))) = 0
then LEN(t.xField)
else charindex(';',substring( t.xField , charindex('Tipton',t.xField) + 8,LEN(t.xField)))-1 end )
else '-' end [Tip Price]
,case
when charindex('AItmPr',t.xField) > 0 then
substring( t.xField , charindex('AItmPr',t.xField) + 8,case when charindex(';',substring( t.xField , charindex('AItmPr',t.xField) + 8,LEN(t.xField))) = 0
then LEN(t.xField)
else charindex(';',substring( t.xField , charindex('AItmPr',t.xField) + 8,LEN(t.xField)))-1 end )
else '-' end [Additional Price]