SQL / DB2 Array in Where declared in with - sql

anyone does know a workaround for querying with parameters/variables for usage in where [...] in functions on db2 v11?
what i tried:
DECLARE #list varchar(23) = '1,2,3,4'
SELECT ...FROM tbl WHERE col IN (#list)
WITH test(val) AS (VALUES(ARRAY['5','9']))
SELECT ... FROM table, test WHERE col ANY(val)
both do not work, first one isn't db2 compatible, the second ones does not work cause he cant split the values.
any ideas or examples?

Try this:
SELECT t.*
FROM tbl t
WHERE EXISTS
(
select 1
from xmltable
(
'for $id in tokenize($s, ",") return <i>{string($id)}</i>'
passing '1,2,3,4' as "s"
columns
tok int path '.'
) v
where v.tok = t.col
);
You may use a parameter marker instead of the string constant 1,2,3,4 as for usual string paramter, if you want to provide such a list of integers as a comma separated string at runtime.

Declare local temporary table and insert your value list in that ?

Related

Checking if field contains multiple string in sql server

I am working on a sql database which will provide with data some grid. The grid will enable filtering, sorting and paging but also there is a strict requirement that users can enter free text to a text input above the grid for example
'Engine 1001 Requi' and that the result will contain only rows which in some columns contain all the pieces of the text. So one column may contain Engine, other column may contain 1001 and some other will contain Requi.
I created a technical column (let's call it myTechnicalColumn) in the table (let's call it myTable) which will be updated each time someone inserts or updates a row and it will contain all the values of all the columns combined and separated with space.
Now to use it with entity framework I decided to use a table valued function which accepts one parameter #searchQuery and it will handle it like this:
CREATE FUNCTION myFunctionName(#searchText NVARCHAR(MAX))
RETURNS #Result TABLE
( ... here come columns )
AS
BEGIN
DECLARE #searchToken TokenType
INSERT INTO #searchToken(token) SELECT value FROM STRING_SPLIT(#searchText,' ')
DECLARE #searchTextLength INT
SET #searchTextLength = (SELECT COUNT(*) FROM #searchToken)
INSERT INTO #Result
SELECT
... here come columns
FROM myTable
WHERE (SELECT COUNT(*) FROM #searchToken WHERE CHARINDEX(token, myTechnicalColumn) > 0) = #searchTextLength
RETURN;
END
Of course the solution works fine but it's kinda slow. Any hints how to improve its efficiency?
You can use an inline Table Valued Function, which should be quite a lot faster.
This would be a direct translation of your current code
CREATE FUNCTION myFunctionName(#searchText NVARCHAR(MAX))
RETURNS TABLE
AS RETURN
(
WITH searchText AS (
SELECT value token
FROM STRING_SPLIT(#searchText,' ') s(token)
)
SELECT
... here come columns
FROM myTable t
WHERE (
SELECT COUNT(*)
FROM searchText
WHERE CHARINDEX(s.token, t.myTechnicalColumn) > 0
) = (SELECT COUNT(*) FROM searchText)
);
GO
You are using a form of query called Relational Division Without Remainder and there are other ways to cut this cake:
CREATE FUNCTION myFunctionName(#searchText NVARCHAR(MAX))
RETURNS TABLE
AS RETURN
(
WITH searchText AS (
SELECT value token
FROM STRING_SPLIT(#searchText,' ') s(token)
)
SELECT
... here come columns
FROM myTable t
WHERE NOT EXISTS (
SELECT 1
FROM searchText
WHERE CHARINDEX(s.token, t.myTechnicalColumn) = 0
)
);
GO
This may be faster or slower depending on a number of factors, you need to test.
Since there is no data to test, i am not sure if the following will solve your issue:
-- Replace the last INSERT portion
INSERT INTO #Result
SELECT
... here come columns
FROM myTable T
JOIN #searchToken S ON CHARINDEX(S.token, T.myTechnicalColumn) > 0

How can I replace multiple words of a string in SQL

Is it possible to replace multiple words in a string in sql without using multiple replace functions?
For example I have a string where I need to replace word 'POLYESTER' with 'POLY' , 'COTTON' with 'CTN', 'GRAPHIC' with 'GRPHC' etc in order to keep the string length at a max of say 30 without much loosing the readability of contents in it(can't use substring to limit chars since it can trim the end meaningful parts of string completely). So we decided to short some keywords like above.
Current query I have used :
SELECT
REPLACE(REPLACE('**Some string value **COTTON **Some string value ** POLYESTER', 'POLYESTER', 'POLY'), 'COTTON', 'CTN')
If I have 10 keywords like this, what will be the best way to achieve the result other than using multiple replace function. I am using SQL Server 2012.
considering sql server is your only instrument (not a c# or another application), as a workaroud; use a temp or persistent table to store replacement options.
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
DROP TABLE #tmp
CREATE TABLE #tmp (
fromText VARCHAR(16),
toText VARCHAR(16)
);
INSERT INTO #tmp (fromText, toText)
VALUES
('POLYESTER', 'POLY'),
('COTTON', 'CTN'),
('GRAPHIC', 'GRPHC')
DECLARE #someValue AS NVARCHAR(MAX) =
'**Some string value **COTTON **Some string value ** POLYESTER';
SELECT #someValue = REPLACE(#someValue, fromText, toText) FROM #tmp;
PRINT #someValue
and the result is:
**Some string value **CTN **Some string value ** POLY.
The answer of mehmetx is actually very nice.
If you need your replacement functionality on a regular basis, you could think about using a normal table instead of a temporary table.
But if you need this logic only once in a while, and performance is not much of an issue, you could avoid the additional replacements table altogether and use a table expression in the FROM clause instead. Something like this:
DECLARE #someValue AS NVARCHAR(MAX) = '**Some string value **COTTON **Some string value ** POLYESTER';
SELECT #someValue = REPLACE(#someValue, fromText, toText)
FROM
(VALUES
('POLYESTER', 'POLY'),
('COTTON', 'CTN'),
('GRAPHIC', 'GRPHC')
) AS S (fromText, toText);
EDIT:
I noticed, that this logic regrettably does not work as expected when used in an UPDATE statement to update existing data in a table.
For that purpose (if needed), I created a user-defined function that performs the replacement logic. I called it MultiReplace. And it does not use the replacement data from a temporary table, but from a "normal" table, which I called Replacements.
The following code demonstrates it. It uses a data table called MyData, which gets updated with all replacements in the Replacements table using the MultiReplace function:
IF OBJECT_ID('MultiReplace') IS NOT NULL
DROP FUNCTION MultiReplace;
IF OBJECT_ID('Replacements') IS NOT NULL
DROP TABLE Replacements;
IF OBJECT_ID('MyData') IS NOT NULL
DROP TABLE MyData;
GO
CREATE TABLE Replacements (
fromText VARCHAR(100),
toText VARCHAR(100)
);
CREATE TABLE MyData (
SomeValue VARCHAR(MAX)
)
GO
CREATE FUNCTION MultiReplace(#someValue AS VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
SELECT #someValue = REPLACE(#someValue, fromText, toText) FROM Replacements;
RETURN #someValue;
END;
GO
INSERT INTO MyData (SomeValue)
VALUES
('**Some string value **COTTON **Some string value ** POLYESTER');
INSERT INTO Replacements (fromText, toText)
VALUES
('POLYESTER', 'POLY'),
('COTTON', 'CTN'),
('GRAPHIC', 'GRPHC');
SELECT * FROM MyData;
UPDATE MyData SET SomeValue = dbo.MultiReplace(SomeValue)
SELECT * FROM MyData;
But perhaps using multiple REPLACE statements might be more straightforward after all?...
EDIT 2:
Based on the short conversation in the comments, I could propose a simpler solution that uses multiple REPLACE statements in a clearer way. I have only tested it on SQL Server 2019; I am not sure if it will work correctly on SQL Server 2012.
Again, I use a table called MyData for testing here. But there are no additional database objects anymore.
Regrettably, I did not get it to work with a temporary table containing the replacement values.
-- Preparations:
IF OBJECT_ID('MyData') IS NOT NULL
DROP TABLE MyData;
CREATE TABLE MyData (
SomeValue VARCHAR(MAX)
);
INSERT INTO MyData
VALUES
('**Some string value **COTTON **Some string value ** POLYESTER'),
('**Another string value **GRAPHIC **Another string value ** POLYESTER');
-- Actual work:
SELECT * FROM MyData; -- Show the state before updating
DECLARE #someValue VARCHAR(MAX);
UPDATE MyData
SET
#someValue = SomeValue,
#someValue = REPLACE(#someValue, 'POLYESTER', 'POLY'),
#someValue = REPLACE(#someValue, 'COTTON', 'CTN'),
#someValue = REPLACE(#someValue, 'GRAPHIC', 'GRPHC'),
SomeValue = #someValue;
SELECT * FROM MyData; -- Show the state after updating

Comparing 2 strings and find out mismatches

I need to create a query in MariaDB 10.2. I am trying to create a query with string functions as now
Below is the scenario
One string has placeholders and another string has values of those placeholders. I want to get a tabular output in which one column have placeholders and another column have placeholder's values
value1 -->
jdbc:postgresql://$PGHOST_1$:$PGPORT_INSTANCE_1$/eventstore
value2 -->
jdbc:postgresql://1.2.3.4:5432/eventstore
now i want to get below data
Thanks in advance.
This needs a looping mechanism. Therefore, use a stored procedure or client code to do the looping:
SELECT placeholder, `value` FROM mylist;
`col` starts out looking like `value1`
foreach row in the list of replacements:
UPDATE mytable SET col =
REPLACE(col, placeholder, `value`);
Now `col` looks like your `value2`
or, if you don't want to change col:
SELECT placeholder, `value` FROM mylist;
SELECT #col := col FROM mytable;
foreach row in the list of replacements:
SET #col =
REPLACE(#col, placeholder, `value`);
then use #col in subsequent work
(value is a keyword, hence the backtics.)
From there, build the "mismatches".

Split comma sepearted from Variable and check if it contains a specific number in Sql server Stored procedure

I have a stored procedure in which i declared a variable and getting multiple values in it (separated with comma)
I want to check if it contains a specific number.If contains then run other queries.
Thanks in Advance :)
Using Aaron Bertrand's split string function you can do something like this.
DECLARE #CSVString NVARCHAR(MAX) = '13,4325,345,987, 432';
DECLARE #Id_To_Find INT = 4325
;WITH cteIdSplit
AS(
SELECT
CAST([Value] AS INT) 'Id'
FROM
dbo.FN_SplitString_AB (#CSVString, ',') A
WHERE
vn = 1
)
SELECT * FROM cteIdSplit S WHERE S.Id = #Id_To_Find;

Create temp table from comma separated values with more than one column

I'm trying to pass a comma separated string such as this: "101:string1,102:string2" into a stored proc and create a temp table out of it. The temp table would have two columns, one integer and one string. It would have two rows for this example. The comma delimits the rows, and the colons delimit the two columns. Anyone know how I can do this? I'm using sql server. Thanks in advance!
EDIT: By the way, I'm not asking about how to create a temp table, only how to create the function.
You can try a Table-Valued Function instead of a temp table. Something like this:
CREATE FUNCTION ListToTable
(
#list nvarchar(4000)
)
RETURNS #return TABLE
(
n int,
s nvarchar(15)
)
AS
BEGIN
SET #list = NULLIF(ltrim(rtrim(#list)),'')
DECLARE #xml AS XML = CAST('<root><row><n>' +
REPLACE(REPLACE(#list,
',', '</s></row><row><n>'),
':', '</n><s>') +
'</s></row></root>' AS XML) ;
INSERT INTO #return (n, s)
SELECT root.row.value('n[1]', 'int')
, root.row.value('s[1]', 'nvarchar(4000)')
FROM #xml.nodes('/root/row') as root(row)
RETURN
END
Usage:
select * from dbo.ListToTable('101:string1,102:string2')
Output:
n s
----------- ---------------
101 string1
102 string2