As example of data from CSV, I have a row:
1;75353;CWB;114#389#115#381#11#382#117#78#118#384;1244;13;4727;15
I would like to get something like that:
1;75353;CWB;114;1244;13;4727;15
1;75353;CWB;389;1244;13;4727;15
1;75353;CWB;115;1244;13;4727;15
1;75353;CWB;381;1244;13;4727;15
1;75353;CWB;11;1244;13;4727;15
1;75353;CWB;382;1244;13;4727;15
1;75353;CWB;117;1244;13;4727;15
1;75353;CWB;78;1244;13;4727;15
1;75353;CWB;118;1244;13;4727;15
1;75353;CWB;384;1244;13;4727;15
I have tried to use (I'm using SQLITE, but I can use MariaDB if needed, also):
select dt2.zone_number, dt2.section_num, dt1.zone, dt1.section, dt1.local, dt1.local_name, dt1.address, dt1.neighbor
from datatable01 as dt1, datatable02 as dt2 where
(
dt1.zone = dt2.zone_number and
instr(dt2.section_num, dt1.section) > 0
)
order by dt1.zone, dt1.local
But... this capture any case. From datatable02, if dt1.section = 11, it's capture 114 from dt2.section_num (example above)
I have tried to use regexp '[0-9]{2,3}', but I got error (syntax error).
Any suggestion to solve it?
Thank you.
I believe the following will do what you want or could be the basis of what you want :-
WITH midparts(w, s) AS (
SELECT '',
/* extract the mid-part i.e. from after CBW; to the next ; */
substr(substr(row1,instr(row1,'CWB;')+length('CWB;')),1,instr(substr(row1,instr(row1,'CWB;')+length('CWB;')),';')-1)||'#'
FROM t01
UNION ALL SELECT
substr(s, 0, instr(s, '#')),
substr(s, instr(s, '#')+1)
FROM midparts WHERE s!=''
),
/* extract the start and end (prefix and suffix) */
startandend(prefix,suffix) AS (
SELECT
substr(row1,1,instr(row1,'CWB;') + length('CWB;') -1),
substr(substr(row1,instr(row1,'CWB;')+length('CWB;')),instr(substr(row1,instr(row1,'CWB;')+length('CWB;')),';'))
FROM t01
)
SELECT (SELECT prefix FROM startandend)||w||(SELECT suffix FROM startandend) AS generated FROM midparts WHERE w!='';
noting that the table with the data has been named t01 and that the row containing the data is row1
Example :-
The above was tested using :-
DROP TABLE IF EXISTS t01;
CREATE TABLE IF NOT EXISTS t01 (row1);
INSERT INTO t01 VALUES('1;75353;CWB;114#389#115#381#11#382#117#78#118#384;1244;13;4727;15');
WITH midparts(w, s) AS (
SELECT '',
/* extract the mid-part i.e. from after CBW; to the next ; */
substr(substr(row1,instr(row1,'CWB;')+length('CWB;')),1,instr(substr(row1,instr(row1,'CWB;')+length('CWB;')),';')-1)||'#'
FROM t01
UNION ALL SELECT
substr(s, 0, instr(s, '#')),
substr(s, instr(s, '#')+1)
FROM midparts WHERE s!=''
),
/* extract the start and end (prefix and suffix) */
startandend(prefix,suffix) AS (
SELECT
substr(row1,1,instr(row1,'CWB;') + length('CWB;') -1),
substr(substr(row1,instr(row1,'CWB;')+length('CWB;')),instr(substr(row1,instr(row1,'CWB;')+length('CWB;')),';'))
FROM t01
)
SELECT (SELECT prefix FROM startandend)||w||(SELECT suffix FROM startandend) AS generated FROM midparts WHERE w!='';
Result :-
Related
I have one string element, for example : "(1111, Tem1), (0000, Tem2)" and hope to generate a data table such as
var1
var2
1111
Tem1
0000
Tem2
This is my code, I created the lag token and filter with odd rows element.
with var_ as (
select '(1111, Tem1), (0000, Tem2)' as pattern_
)
select tbb1.*, tbb2.result_string as result_string_previous
from(
select tb1.*,
min(token) over(partition by 1 order by token asc rows between 1 preceding and 1 preceding) as min_token
from
table (
strtok_split_to_table(1, var_.pattern_, '(), ')
returns (outkey INTEGER, token INTEGER, result_string varchar(20))
) as tb1) tbb1
inner join (select min_token, result_string from tbb1) tbb2
on tbb1.token = tbb2.min_token
where (token mod 2) = 0;
But it seems that i can't generate new variables in "from" step and applied it directly in "join" step.
so I wanna ask is still possible to get the result what i want in my procedure? or is there any suggestion?
Thanks for all your assistance.
I wouldn't split / recombine the groups. Split each group to a row, then split the values within the row, e.g.
with var_ as (
select '(1111, Tem1), (0000, Tem2)' as pattern_
),
split1 as (
select trim(leading '(' from result_string) as string_
from
table ( /* split at & remove right parenthesis */
regexp_split_to_table(1, var_.pattern_, '\)((, )|$)','c')
returns (outkey INTEGER, token_nbr INTEGER, result_string varchar(256))
) as tb1
)
select *
from table(
csvld(split1.string_, ',', '"')
returns (var1 VARCHAR(16), var2 VARCHAR(16))
) as tb2
;
I've got a report that has 6 parameters. All parameters need to be optional and 3 have to be multi-value. One of the optional parameters is a dropdown, the rest are manually keyed in text boxes.
The Where clause below works when there are multiple #VendorNum values and one #FullJA value, but fails with multiple #FullJA values regardless of the #VendorNum count.
Parameters:
#VendorNum - keyed manually by user (space delimited) - optional, can be multivalue
#FullJA - keyed manually by user (space delimited) - optional, can be multivalue
#BU - optional, can be multivalue - when #JA is populated, this will auto-populate, if #JA isn't populated it's a dropdown with all selected.
#JA3 - keyed by user - optional, single value
#StartDate and #EndDate - optional single values
select * from some_table
WHERE
/*FULL JA*/
(
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND LEFT(JA, 7) IN (#FullJA)
AND BU IN(#BU)
AND #JA3 IS NULL
)
OR
/*DATE RANGE*/
(
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND LEN(ISNULL(CONVERT(VARCHAR(20), Cleared_When), '0')) >= #ClearedOnly
AND ad.Audit_Publish_Date >= ISNULL(#StartDate, '2015-01-01')
AND ad.Audit_Publish_Date <= ISNULL(#EndDate, '2025-12-31')
AND BU IN (#BU)
AND #FullJA IS NULL
AND #JA3 IS NULL
)
/*BUS UNIT AND JA3*/
OR (
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND BU IN (#BU)
AND ad.Audit_Publish_Date >= ISNULL(#StartDate, '2015-01-01')
AND ad.Audit_Publish_Date <= ISNULL(#EndDate, '2025-12-31')
AND LEFT(JA, 3) = (#JA3)
AND #FullJA IS NULL
)
/*BUS UNIT ONLY*/
OR (
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND BU IN (#BU)
AND ad.Audit_Publish_Date >= ISNULL(#StartDate, '2015-01-01')
AND ad.Audit_Publish_Date <= ISNULL(#EndDate, '2025-12-31')
AND #JA3 IS NULL
AND #FullJA IS NULL
)
The dataset parameter values for #FullJA and #VendorNum are both
=IIF(InStr(Parameters!FullJA.Value," ")>0,SPLIT(Parameters!FullJA.Value," "),Parameters!FullJA.Value) and all params are set as NOT multivalue, with nulls allowed.
Any help would be greatly appreciated. I've written over 200 reports for this project and this is the only one that is really grinding my gears!
Thanks!
I would approach this by building up some temp tables / table variables, to hold the potentially multi-valued variables, and then joining to those tables. This has the advantage of you being able to insert all possible values, in the case they have omitted the variable. So, you'd split your strings and put them into those tables (something along the lines of this example) if given the variable, and otherwise just do an insert into to populate your temp table / table variable.
For a split function, I prefer something like this:
create FUNCTION [dbo].[Split] (#sep VARCHAR(32), #s VARCHAR(MAX))
RETURNS TABLE
AS
RETURN
(
SELECT r.value('.','VARCHAR(MAX)') as Item
FROM (SELECT CONVERT(XML, N'<root><r>' + REPLACE(REPLACE(REPLACE(#s,'& ','& '),'<','<'), #sep, '</r><r>') + '</r></root>') as valxml) x
CROSS APPLY x.valxml.nodes('//root/r') AS RECORDS(r)
)
GO
GRANT SELECT
ON OBJECT::[dbo].[Split] TO PUBLIC
AS [dbo];
I would then put those variables into a table using something like this (my separator is a ", "):
select ltrim(rtrim(ppl.Item)) as PersonName
into #gppl
from dbo.Split(', ', #PersonListForCompare) as ppl
You would do something more like:
select ltrim(rtrim(vnd.Item)) as VendorNum
into #vendorNums
from dbo.Split(', ', #VendorNum) as vnd
You would then join to that temp table just like any other table & use it to limit your results that way. In your case, you want to put in all vendors (possibly) if they didn't give you any input. So, you'd do something like:
create table #vendorNums (VendorName varchar(64)) --I have no idea, here, what this data looks like
if #VendorNum is not null and datalength(#VendorNum) > 0
insert into into #vendorNums (VendorNum)
select ltrim(rtrim(vnd.Item))
from dbo.Split(', ', #VendorNum) as vnd
else
insert into into #vendorNums (VendorNum)
select VendorNum
from dbo.Vendors
That said, I think that you could use your select from dbo.Split directly as a table in a join, rather than putting it into the temp table. Only problem would be you'd have to be sure you had data in there to split, or else you're going to have a bunch of combinations to get the right match-up of null parameters vs. filled ones.
Is it possible to sum the digits in a string and sort by that?
Example values: 19, 21
19 Should be transformed to 10. Explanation: 1+9=10
21 Should be transformed to 3. Explanation: 2+1= 3
After calculating these results, the table needs to be sorted by the resulting values (using SORT BY).
Originally, I have those values stored as JSON array, so it's ["1","9"] and ["2","1"], and in order to parse the JSON I'm using replace as follows:
REPLACE(REPLACE(REPLACE(item_qty, '["', ''), '"]', ''), '","', '')
How about trying something like:
SELECT (
SUBSTRING('["1","9"]', 3, 3) +
SUBSTRING('["1","9"]', 7, 7)
) AS sumOfDigits;
And then if the value ["1","9"] is stored in a column named json and the table is named table you van do:
SELECT * FROM (
SELECT table.*, (
SUBSTRING('json', 3, 3) +
SUBSTRING('json', 7, 7)
) AS sumOfDigits
FROM table
) tmp
ORDER BY sumOfDigits;
I would define a function to do the sum, as follow:
DELIMITER //
CREATE FUNCTION add_digits
(
number INTEGER
) RETURNS INTEGER
BEGIN
DECLARE my_sum INTEGER;
SET my_sum = 0;
SET number = ABS(number);
WHILE (number > 0) DO
SET my_sum = my_sum + (number MOD 10);
SET number = number DIV 10;
END WHILE;
RETURN my_sum;
END //
DELIMITER ;
You could also create a function that works directly on your json sting, parsing it for digits and adding their values.
There is a SQL table mytable that has a column mycolumn.
That column has text inside each cell. Each cell may contain "this.text/31/" or "this.text/72/" substrings (numbers in that substrings can be any) as a part of string.
What SQL query should be executed to display a list of unique such substrings?
P.S. Of course, some cells may contain several such substrings.
And here are the answers for questions from the comments:
The query supposed to work on SQL Server.
The prefered output should contain the whole substring, not the numeric part only. It actually could be not just the number between first "/" and the second "/".
And it is varchar type (probably)
Example:
mycolumn contains such values:
abcd/eftthis.text/31/sadflh adslkjh
abcd/eftthis.text/44/khjgb ljgnkhj this.text/447/lhkjgnkjh
ljgkhjgadsvlkgnl
uygouyg/this.text/31/luinluinlugnthis.text/31/ouygnouyg
khjgbkjyghbk
The query should display:
this.text/31/
this.text/44/
this.text/447/
How about using a recursive CTE:
CREATE TABLE #myTable
(
myColumn VARCHAR(100)
)
INSERT INTO #myTable
VALUES
('abcd/eftthis.text/31/sadflh adslkjh'),
('abcd/eftthis.text/44/khjgb ljgnkhj this.text/447/lhkjgnkjh'),
('ljgkhjgadsvlkgnl'),
('uygouyg/this.text/31/luinluinlugnthis.text/31/ouygnouyg'),
('khjgbkjyghbk')
;WITH CTE
AS
(
SELECT MyColumn,
CHARINDEX('this.text/', myColumn, 0) AS startPos,
CHARINDEX('/', myColumn, CHARINDEX('this.text/', myColumn, 1) + 10) AS endPos
FROM #myTable
WHERE myColumn LIKE '%this.text/%'
UNION ALL
SELECT T1.MyColumn,
CHARINDEX('this.text/', T1.myColumn, C.endPos) AS startPos,
CHARINDEX('/', T1.myColumn, CHARINDEX('this.text/', T1.myColumn, c.endPos) + 10) AS endPos
FROM #myTable T1
INNER JOIN CTE C
ON C.myColumn = T1.myColumn
WHERE SUBSTRING(T1.MyColumn, C.EndPos, 100) LIKE '%this.text/%'
)
SELECT DISTINCT SUBSTRING(myColumn, startPos, EndPos - startPos)
FROM CTE
Having a table named test with the following data:
COLUMN1
aathis.text/31/
this.text/1/
bbbthis.text/72/sksk
could this be what you are looking for?
select SUBSTR(COLUMN1,INSTR(COLUMN1,'this.text', 1 ),INSTR(COLUMN1,'/',INSTR(COLUMN1,'this.text', 1 )+10) - INSTR(COLUMN1,'this.text', 1 )+1) from test;
result:
this.text/31/
this.text/1/
this.text/72/
i see your problem:
Assume the same table as above but now with the following data:
this.text/77/
xxthis.text/33/xx
xthis.text/11/xxthis.text/22/x
xthis.text/1/x
The following might help you:
SELECT SUBSTR(COLUMN1, INSTR(COLUMN1,'this.text', 1 ,1), INSTR(COLUMN1,'/',INSTR(COLUMN1,'this.text', 1 ,1)+10) - INSTR(COLUMN1,'this.text', 1 ,1)+1) FROM TEST
UNION
SELECT CASE WHEN (INSTR(COLUMN1,'this.text', 1,2 ) >0) THEN
SUBSTR(COLUMN1, INSTR(COLUMN1,'this.text', 1,2 ), INSTR(COLUMN1,'/',INSTR(COLUMN1,'this.text', 1 ,2),2) - INSTR(COLUMN1,'this.text', 1,2 )+1) end FROM TEST;
it will generate the following result:
this.text/1/
this.text/11/
this.text/22/
this.text/33/
this.text/77/
The downside is that you need to add a select statement for every occurance you might have of "this.text". If you might have 100 "this.text" in the same cell it might be a problem.
SQL> select SUBSTR(column_name,1,9) from tablename;
column_name
this.text
SELECT REGEXP_SUBSTR(column_name,'this.text/[[:digit:]]+/')
FROM table_name
url link
1.247appliances.co.uk info#247appliances.co.uk info#247appliances.co.uk
2.365electrical.com sales#365electrical.com sales#365electrical.com sales#365electrical.com sales#365electrical.com|customerservices#365electrical.com sales#365electrical.com
in the above table first row and second row link column has repeated values but in need the result to be
url link
1.247appliances.co.uk info#247appliances.co.uk
2.365electrical.com sales#365electrical.com customerservices#365electrical.com
Used DISTINCT when calling column here is sample
SELECT DISTINCT column_name,column_name
FROM table_name;
This might not be an exact solution to your issue but I have tried to give you an idea.
Cheers
First create a Split Function
CREATE FUNCTION dbo.Split (#sep CHAR(1), #s VARCHAR(512))
RETURNS TABLE
AS
RETURN (
WITH Pieces(pn, START, stop) AS (
SELECT 1, 1, CHARINDEX(#sep, #LinkValue)
UNION ALL
SELECT pn + 1, stop + 1, CHARINDEX(#sep, #LinkValue, stop + 1)
FROM Pieces
WHERE stop > 0
)
SELECT pn,
SUBSTRING(#LinkValue, START, CASE WHEN stop > 0 THEN stop-START ELSE 512 END) AS Link
FROM Pieces
)
I have created a temporary table for sample data (use your own table)
CREATE TABLE #RemoveDuplicateWords (URL VARCHAR(200), Link VARCHAR(200))
GO
INSERT INTO #RemoveDuplicateWords(URL,Link)
SELECT '1.247appliances.co.uk', 'info#247appliances.co.uk info#247appliances.co.uk'
UNION ALL
SELECT '2.365electrical.com','sales#365electrical.com sales#365electrical.com sales#365electrical.com'
GO
And Finally a SELECT query
SELECT
rd.URL,
st.Link
FROM #RemoveDuplicateWords rd
CROSS APPLY dbo.Split(' ',rd.LINK) AS st
GROUP BY
rd.URL,
st.Link