How to manipulate comma-separated list in SQL Server - sql

I have a list of values such as
1,2,3,4...
that will be passed into my SQL query.
I need to have these values stored in a table variable. So essentially I need something like this:
declare #t (num int)
insert into #t values (1),(2),(3),(4)...
Is it possible to do that formatting in SQL Server? (turning 1,2,3,4... into (1),(2),(3),(4)...
Note: I can not change what those values look like before they get to my SQL script; I'm stuck with that list. also it may not always be 4 values; it could 1 or more.
Edit to show what values look like: under normal circumstances, this is how it would work:
select t.pk
from a_table t
where t.pk in (#place_holder#)
#placeholder# is just a literal place holder. when some one would run the report, #placeholder# is replaced with the literal values from the filter of that report:
select t.pk
from a_table t
where t.pk in (1,2,3,4) -- or whatever the user selects
t.pk is an int
note: doing
declare #t as table (
num int
)
insert into #t values (#Placeholder#)
does not work.

Your description is a bit ridicuolus, but you might give this a try:
Whatever you mean with this
I see what your trying to say; but if I type out '#placeholder#' in the script, I'll end up with '1','2','3','4' and not '1,2,3,4'
I assume this is a string with numbers, each number between single qoutes, separated with a comma:
DECLARE #passedIn VARCHAR(100)='''1'',''2'',''3'',''4'',''5'',''6'',''7''';
SELECT #passedIn; -->: '1','2','3','4','5','6','7'
Now the variable #passedIn holds exactly what you are talking about
I'll use a dynamic SQL-Statement to insert this in a temp-table (declared table variable would not work here...)
CREATE TABLE #tmpTable(ID INT);
DECLARE #cmd VARCHAR(MAX)=
'INSERT INTO #tmpTable(ID) VALUES (' + REPLACE(SUBSTRING(#passedIn,2,LEN(#passedIn)-2),''',''','),(') + ');';
EXEC (#cmd);
SELECT * FROM #tmpTable;
GO
DROP TABLE #tmpTable;
UPDATE 1: no dynamic SQL necessary, all ad-hoc...
You can get the list of numbers as derived table in a CTE easily.
This can be used in a following statement like WHERE SomeID IN(SELECT ID FROM MyIDs) (similar to this: dynamic IN section )
WITH MyIDs(ID) AS
(
SELECT A.B.value('.','int') AS ID
FROM
(
SELECT CAST('<x>' + REPLACE(SUBSTRING(#passedIn,2,LEN(#passedIn)-2),''',''','</x><x>') + '</x>' AS XML) AS AsXml
) as tbl
CROSS APPLY tbl.AsXml.nodes('/x') AS A(B)
)
SELECT * FROM MyIDs
UPDATE 2:
And to answer your question exactly:
With this following the CTE
insert into #t(num)
SELECT ID FROM MyIDs
... you would actually get your declared table variable filled - if you need it later...

Related

sql query to create a table at runtime and insert the values in it from the select statement from the database

what i am tryin to do is make a table(#tbl) runtime and insert the data from the select statement from the database,as what i have done so far is
declare #tbl TABLE (
Item int
)
begin
insert into #tbl values select cid from tbl_custumer where cus_ph like '%'+'987'+'%'
select * from #tbl
end
as "select cid" statement returns multiple records
I think you might want the code to look like this:
begin
declare #tbl TABLE (
Item int
);
insert into #tbl(Item)
select cid
from tbl_custumer
where cus_ph like '%'+'987'+'%';
select *
from #tbl;
end;
Notes:
The begin/end block is not really necessary, but I'm guessing you want it for other reasons (a stored procedure, if, or something similar).
The values keyword is not needed when using insert . . . select.
Use semicolons at the end of each SQL statement. Although they are optional, they make the code easier to follow.

How to store multiple values in a SQL Server variable

I want to store values from a SELECT statement into a variable which is capable of holding more than one value because my SELECT statement returns multiple values of type INT. This is how my SP looks like so far.
ALTER PROCEDURE "ESG"."SP_ADD"
AS
BEGIN
DECLARE #Id table(identifiers VARCHAR);
INSERT INTO #Id (identifiers) VALUES('axaa1aaa-aaaa-a5aa-aaaa-aa8aaaa9aaaa');
INSERT INTO #Id (identifiers) VALUES('bxbb1bbb-bbbb-b5bb-bbb4-bb8bbbb9bbbf');
DECLARE #tranID INT = (SELECT
DOCUMENT_SET_.DOCUMENT_SET_TRANSACTION_ID
FROM DOCUMENT_SET_TRANSACTION
WHERE DOCUMENT_SET_TRANSACTION.IDENTIFIER IN (SELECT identifiers FROM #Id));
END
Variable #tranID should be a list or an array to hold the ids. Is it possible to do it SQL Server?
You can declare a variable of type table
DECLARE #tblTrans TABLE (
tranID INT
);
INSERT INTO #tblTrans
SELECT DOCUMENT_SET_TRANSACTION.DOCUMENT_SET_TRANSACTION_ID
FROM ESG.DOCUMENT_SET_TRANSACTION
WHERE DOCUMENT_SET_TRANSACTION.IDENTIFIER
IN (SELECT identifiers FROM #envelopeId);
Depending on what you want to do with the values after this, you could declare a cursor to loop through them or select straight from the variable.
You could also look into using a temporary table depending on what scope you need.
Try this, only take the firs row of example. Do u try this?
select DOCUMENT_SET_TRANSACTION.DOCUMENT_SET_TRANSACTION_ID,
(STUFF((SELECT '-' + convert(varchar(max),DOCUMENT_SET_TRANSACTION.DOCUMENT_SET_TRANSACTION_ID)
FROM ESG.DOCUMENT_SET_TRANSACTION
FOR XML PATH ('')), 1, 2, '')) AS example
FROM ESG.DOCUMENT_SET_TRANSACTION

SELECT #local_variable=values from table where values can have multiple values

I am using below query
SELECT #local_variable=Adtid from table where Adtid can have multiple values stored into it. As I don't know what to use instead of '=' in #local_variable=Adtid. Can anyone suggest please what I should use instead of '=' so that my local varaible can have all values of Adtid
The variable can't actually hold multiple values. You can declare a table variable instead, where you can then do something like
declare #tableVariable table
(
Adtid int
);
insert into #tableVariable
select Adtid from table where Adtid ...
This puts the relevant rows inside your table variable. Now you can use the table variable to eg. create a cursor (to go row by row in the data - you can also do that on the original select if you only need to go through once) or use it in a join clause.
You can use below syntax for get the Adtid as comma separator in result
DECLARE #local_variable VARCHAR(100) =''
SELECT #local_variable += CAST(Adtid AS VARCHAR) + ',' FROM TABLE
PRINT #local_variable
and another way as per below answer.

How to minimize sql select?

I have an array of words like this one:
$word1 = array('test1','test2','test3','test4','test5',...,'test20');
I need to search in my table every row that has at least one of these words in the text column. So far, I have this sql query:
SELECT * FROM TABLE WHERE text LIKE '$word1[0]' OR text LIKE '$word1[1]'
OR ... OR text LIKE '$word1[20]'
But I see that this design isn't very efficient. Is there any way I can shorten this query, in such a way that I don't need to write out every word in the where clause?
Example SELECT * FROM TABLE WHERE text IN ($word1)
P.S.: this is an example of what I'm looking for, not an actual query I can run.
If you use a table variable instead of a list to store your words then you can use something like:
DECLARE #T TABLE (Word VARCHAR(255) NOT NULL);
INSERT #T (Word)
VALUES ('test1'), ('test2'), ('test3'), ('test4'), ('test5'), ('test20');
SELECT *
FROM TABLE t
WHERE EXISTS
( SELECT 1
FROM #T
WHERE t.Text LIKE '%' + word + '%'
);
You can also create a table type to store this, then you can pass this as a parameter to a stored procedure if required:
CREATE TYPE dbo.StringList (Value VARCHAR(MAX) NOT NULL);
GO
CREATE PROCEDURE dbo.YourProcedures #Words dbo.StringList READONLY
AS
SELECT *
FROM TABLE t
WHERE EXISTS
( SELECT 1
FROM #Words w
WHERE t.Text LIKE '%' + w.word + '%'
);
GO
DECLARE #T dbo.StringList;
INSERT #T (Value)
VALUES ('test1'), ('test2'), ('test3'), ('test4'), ('test5'), ('test20');
EXECUTE dbo.YourProcedure #T;
For more on this see table-valued Parameters on MSDN.
EDIT
I may have misunderstood your requirements as you used LIKE but with no wild card operator, in which case you can just use IN, however I would still recommend using a table to store your values:
DECLARE #T TABLE (Word VARCHAR(255) NOT NULL);
INSERT #T (Word)
VALUES ('test1'), ('test2'), ('test3'), ('test4'), ('test5'), ('test20');
SELECT *
FROM TABLE t
WHERE t.Text IN (SELECT Word FROM #T);
You can use a SELECT like this without declaring an array:
SELECT * FROM TABLE WHERE text IN ('test1', 'test2', 'test3', 'test4', 'test5')
One solution could be :
Create a table in the database with the searched words in a column called word (by example)- by using wildcard if you need
use this kind of request
SELECT *
FROM TABLE, FILTER_TABLE
WHERE TABLE.text LIKE FILTER_TABLE.word
Although I don't have access to SQL Server 2008 at the moment and SQLfiddle seems sick, it would seem you can use a table value constructor to simplify the expression somewhat;
SELECT * FROM test
JOIN (SELECT w FROM (VALUES('word1'), ('word2'), ('word3'), ('word4')) AS a(w)) a
ON test.text LIKE '%'+a.w+'%';
...which will search the text column in the test table for the words listed as values. If you don't want duplicates of rows where multiple words match, you can just add a DISTINCT to the select.
Note though that you may want to look into fulltext indexing if you're doing extensive searches, a LIKE query to find words in a string in this way will not use any indexes, and will most likely be quite slow unless the data is already in memory.

Referring to column values directly without using variables in T-SQL

Is there a way in T-SQL (SQL Server 2005) to assign a whole record to a record variable and then refer to the particular values using column names?
I mean, instead of:
select #var1 = col1,
#var2 = col2
from mytable
where ID = 1;
and referring to them as #var1 and #var2, something like
#record =
select col1, col2
from mytable
where ID = 1;
and referring to them like #record.col1 and #record.col2 .
I am beginner in t-sql, so hopefully the question is not too trivial.
You can create a table variable and select the whole resultset into it:
DECLARE #tt TABLE (col1 INT, col2 INT)
INSERT
INTO #tt
SELECT col1, col2
FROM mytable
WHERE id = 1
, but you cannot access its data except than in the SELECT query as well.
With pure TSQL (that it without custom datatypes) the thing you ask is impossible.
sounds like you are a programmer ... look at linq maybe as it does what you want.
You can use a temporary table and SELECT...INTO to avoid specifying the column names at the beginning :
SELECT Field1, Field2
INTO #TempTable
FROM MyTable
WHERE MyTable.MyID = 1
but of course you'll still need the FROM #TempTable part when referring to the column names.
SELECT Field1, Field2
FROM #TempTable
and of course to remember to drop the table at the end :
DROP #TempTable
The app code is where you'd normally refer to a single row at a time as a variable.
You could use XML, but you'd have to play with this...
DECLARE #MyRecord xml
DECLARE #Mytable TABLE (col1 int NOT NULL, col2 varchar(30) NOT NULL)
INSERT #Mytable (col1, col2) VALUES (1, 'bob')
select #MyRecord =
(SELECT *
from #Mytable
where col1 = 1
FOR XML AUTO)
SELECT #myRecord.value('./#col', 'int') --also #myRecord.value('#col', 'int')
--gives error
Msg 2390, Level 16, State 1, Line 12
XQuery [value()]: Top-level attribute nodes are not supported
Buried in the Transact SQL documentation I came across this restriction on variables:
Variables can be used only in expressions, not in place of object names or keywords.
Since you'd need to use an object name to qualify a column I don't believe that this is allowed.