Select IN on more than 2100 values - tsql

How can you do a select in on more than 2100 values?
<cfquery name="result.qryData">
SELECT sub_acct_no, ...
FROM dbo.Closed_ORDER
WHERE ord_no IN <cfqueryparam cfsqltype="CF_SQL_varchar" value="#ValueList(qryOrd.ord_no)#" list="yes">
</cfquery>
Because of the ways that the tables are setup, linked Servers and JOINS are not an option.
When this is ran an error this thrown because there are new many fields being passed in.

First load the values into XML
<cfset var strResult = '<ul class="xoxo">'>
<cfloop query="qryOrd">
<cfset strResult &= '<li>#xmlformat(ord_no)#</li>'>
</cfloop>
<cfset strResult &= '</ul>'>
Then use the xml in the sql query
<cfquery name="result.qryData">
DECLARE #xmlOrd_no xml = <cfqueryparam cfsqltype="CF_SQL_varchar" value="#strResult#">
DECLARE #tblOrd_no TABLE (ID varchar(20))
INSERT INTO #tblOrd_no
SELECT tbl.Col.value('.', 'varchar(20)')
FROM #xmlOrd_no.nodes('/ul/li') tbl(Col)
SELECT sub_acct_no, ...
FROM dbo.Closed_ORDER
WHERE ord_no IN (SELECT ID FROM #tblOrd_no)
</cfquery>
You can also do a dump of the XML and it is properly formatted in HTML
<cfoutput>#strResult#</cfoutput>

Related

SQL Server Merge Statement compilation throw error Incorrect syntax near the keyword WHEN

I have use sql server merge statement and when compiling the my Store procedure then getting this error.
Incorrect syntax near the keyword WHEN
Please have a look at my code and tell me where i have made the mistake.
CREATE TABLE #TmpTenQKData
(
Section NVARCHAR(MAX),
LineItem NVARCHAR(MAX),
XFundCode NVARCHAR(MAX),
StandardDate NVARCHAR(MAX),
StandardValue VARCHAR(MAX),
ActualProvidedByCompany VARCHAR(MAX)
)
BEGIN
INSERT INTO #TmpTenQKData
SELECT col.value('(Section/text())[1]', 'NVARCHAR(MAX)') AS Section
,col.value('(LineItem/text())[1]', 'NVARCHAR(MAX)') AS LineItem
,col.value('(XFundCode/text())[1]', 'NVARCHAR(MAX)') AS XFundCode
,col.value('(StandardDate/text())[1]', 'NVARCHAR(MAX)') AS StandardDate
,col.value('(StandardValue/text())[1]', 'VARCHAR(MAX)') AS StandardValue
,col.value('(ActualProvidedByCompany/text())[1]', 'VARCHAR(MAX)') AS ActualProvidedByCompany
FROM #BogyXML.nodes('/Root/PeriodicalData') AS tab (col)
END
BEGIN
Merge into TblLineItemTemplate as Trg
Using #TmpTenQKData as Src
on UPPER(TRIM(Trg.LineItem))=UPPER(TRIM(Src.LineItem)) AND Trg.TickerID=#TickerID
WHEN MATCHED THEN
UPDATE SET
Trg.XFundCode=Src.XFundCode,
Action='U',
Insertdate=GETDATE();
WHEN NOT MATCHED BY Trg THEN
INSERT TblLineItemTemplate
(
TickerID,
LineItem,
XFundCode,
Action,
UserID,
Insertdate
)
VALUES
(
TRIM(#TickerID),
TRIM(Src.LineItem),
TRIM(Src.XFundCode),
'I',
#UserID,GETDATE()
);
END
Please tell me what to change in code. Thanks
This parses correctly, if it does what you want is another question:
MERGE INTO TblLineItemTemplate Trg
USING #TmpTenQKData Src ON UPPER(TRIM(Trg.LineItem)) = UPPER(TRIM(Src.LineItem)) --Do you really need UPPER()? Are you using a case sensitive collation?
AND Trg.TickerID = #TickerID
WHEN MATCHED THEN UPDATE SET XFundCode = Src.XFundCode,
Action = 'U',
Insertdate = GETDATE()
WHEN NOT MATCHED THEN INSERT (TickerID,
LineItem,
XFundCode,
Action,
UserID,
Insertdate)
VALUES (TRIM(#TickerID), TRIM(Src.LineItem), TRIM(Src.XFundCode), 'I', #UserID, GETDATE());

Prevent lines appearing in XML

I have the following table and content:
CREATE TABLE [dbo].[MyTable](
[PID] [int] NOT NULL,
[CID] [int] NOT NULL
)
INSERT INTO MyTable values (17344,17345)
INSERT INTO MyTable values (17344,17346)
INSERT INTO MyTable values (17272,17273)
INSERT INTO MyTable values (17272,17255)
INSERT INTO MyTable values (17272,17260)
INSERT INTO MyTable values (17272,17274)
INSERT INTO MyTable values (17272,17252)
From this I need to create the following XML layout:
<Item code="17344">
<BOMs>
<BOM code="17344">
<BOMLine type="17345"/>
<BOMLine type="17346"/>
</BOM>
</BOMs>
</Item>
<Item code="17272">
<BOMs>
<BOM code="17272">
<BOMLine type="17273"/>
<BOMLine type="17255"/>
<BOMLine type="17260"/>
<BOMLine type="17274"/>
<BOMLine type="17252"/>
</BOM>
</BOMs>
</Item>
I'm trying to achieve this with the following statement which gives me far too much lines and duplicates:
DECLARE #test XML
SELECT #test =
(SELECT PID '#code',
(SELECT PID as '#code',
(SELECT CID as '#type'
FROM MyTable
FOR XML PATH('BOMLine'), TYPE)
FROM MyTable GROUP BY PID
FOR XML PATH('BOM'), TYPE, ROOT('BOMs'))
FROM MyTable
FOR XML PATH('Item'), TYPE)
select #test
Can anyone help me with this? I'm using SQL Server 2008 by the way.
It would be greatly appreciated.
Best regards,
Wes
You need the group by in the outermost query and you need to make your sub-query correlated with the outer query on PID.
The extra PID in BOM does not need a from clause.
select T1.PID as '#Code',
(
select T1.PID as '#code',
(
select T2.CID as '#type'
from dbo.MyTable as T2
where T1.PID = T2.PID
for xml path('BOMLine'), type
)
for xml path('BOM'), root('BOMs'), type
)
from dbo.MyTable as T1
group by T1.PID
for xml path('Item')

How to get list of database with condition in t-sql

How can i get list of databases?
Select database if have table "test_table".
I don't now how to set condition in
SELECT * FROM master.dbo.sysdatabases
You can build a dynamic query that checks sys.tables in each database.
declare #S1 nvarchar(max)
declare #S2 nvarchar(max)
set #S2 = ' union all select ''[DBNAME]'' from [DBNAME].sys.tables where name = ''test_table'''
select #S1 = stuff((select replace(#S2, '[DBNAME]', quotename(name))
from master.dbo.sysdatabases
for xml path('')), 1, 11, '')
exec (#S1)

Passing In Array Like Variables T-SQL

I can someone help me turn this sql into a stored proc..
select * from voilets
where cfrw = 'F16'
UNION
(select *
from voilets
where cfrw in ('B05','B12','R02','F01','F16','F17','U11','U03','U04','U21'))
ORDER BY DSCA
Where 'F16 is a variable called #default
and
'B05','B12','R02','F01','F16','F17','U11','U03','U04','U21' is an array of #voilets
This is not working for me:
#sCarrierSelect varchar(max)
AS
BEGIN
declare #SQL nvarchar(4000)
set #SQL = '
select * from voilets
where t_cfrw = ' + #default + '
UNION
(select *
from carriers
where t_cfrw in (' + #voilets+'))
ORDER BY T_DSCA
'
print #SQL
exec sp_executesql #SQL
END
IF you SQL Server IS >=2008 then:
USE tempdb;
GO
CREATE TABLE voilets
(cfrw char(3), DSCA int)
go
INSERT INTO voilets VALUES ('R02', 2)
INSERT INTO voilets VALUES ('F16', 5)
INSERT INTO voilets VALUES ('F16', 4)
INSERT INTO voilets VALUES ('X77', 9)
go
CREATE TYPE myType AS TABLE (id CHAR(3));
GO
CREATE PROCEDURE usp_myProc
#default char(3),
#voiletsTVP myType READONLY
AS
select * from voilets
where cfrw = #default
UNION
(select *
from voilets
where cfrw in (SELECT * FROM #voiletsTVP))
ORDER BY DSCA
GO
-------------------------
DECLARE #default char(3)
SET #default='F16'
DECLARE #voiletsTVP AS myType;
INSERT INTO #voiletsTVP SELECT * FROM (VALUES ('B05'),('B12'),('R02'),('F01'),('F16'),('F17'),('U11'),('U03'),('U04'),('U21')) q(x)
EXEC usp_myProc #default,#voiletsTVP
GO
Result-set:
cfrw DSCA
R02 2
F16 4
F16 5
Performing that safely in a sproc is actually quite tricky; there are a few common approaches:
use a udf to split a string on a token - google for "split udf" (there will be many), and join on the results
use a table valued parameter
Personally, I rarely use sprocs these days; I'd use dapper:
List<string> foo = ...
var items = conn.Query<SomeType>(
"select * from [table] where colName in #foo", new { foo }).ToList();
Most LINQ providers and ORMs will have options here too, involving Contains etc.
You can learn about Passing Arrays in SQL Parameters using XML Data Type in SQL Server 2005
See sample:
/* for this xml:
<list>
<item>42</item>
<item>73</item>
<item>2007</item>
</list>
*/
CREATE FUNCTION [lm].[SplitList]
(
#list AS XML
)
RETURNS TABLE
AS
RETURN
(
SELECT tempTable.item.value('.', 'VARCHAR(MAX)') AS Item
FROM #list.nodes('list/item') tempTable(item)
);
Why not use a sql CLR function to split your values, passing those into your procedure. Here is a very good and fast split string implementation: CLR Split String. If you can't use sql clr, then look online for 'sql split string'. Whichever you use you put the result of that work into a temporary table and join that to your main table.

Convert multiple rows into one with comma as separator [duplicate]

This question already has answers here:
How to concatenate text from multiple rows into a single text string in SQL Server
(47 answers)
Closed 7 years ago.
If I issue SELECT username FROM Users I get this result:
username
--------
Paul
John
Mary
but what I really need is one row with all the values separated by comma, like this:
Paul, John, Mary
How do I do this?
select
distinct
stuff((
select ',' + u.username
from users u
where u.username = username
order by u.username
for xml path('')
),1,1,'') as userlist
from users
group by username
had a typo before, the above works
This should work for you. Tested all the way back to SQL 2000.
create table #user (username varchar(25))
insert into #user (username) values ('Paul')
insert into #user (username) values ('John')
insert into #user (username) values ('Mary')
declare #tmp varchar(250)
SET #tmp = ''
select #tmp = #tmp + username + ', ' from #user
select SUBSTRING(#tmp, 0, LEN(#tmp))
good review of several approaches:
http://blogs.msmvps.com/robfarley/2007/04/07/coalesce-is-not-the-answer-to-string-concatentation-in-t-sql/
Article copy -
Coalesce is not the answer to string concatentation in T-SQL I've seen many posts over the years about using the COALESCE function to get string concatenation working in T-SQL. This is one of the examples here (borrowed from Readifarian Marc Ridey).
DECLARE #categories varchar(200)
SET #categories = NULL
SELECT #categories = COALESCE(#categories + ',','') + Name
FROM Production.ProductCategory
SELECT #categories
This query can be quite effective, but care needs to be taken, and the use of COALESCE should be properly understood. COALESCE is the version of ISNULL which can take more than two parameters. It returns the first thing in the list of parameters which is not null. So really it has nothing to do with concatenation, and the following piece of code is exactly the same - without using COALESCE:
DECLARE #categories varchar(200)
SET #categories = ''
SELECT #categories = #categories + ',' + Name
FROM Production.ProductCategory
SELECT #categories
But the unordered nature of databases makes this unreliable. The whole reason why T-SQL doesn't (yet) have a concatenate function is that this is an aggregate for which the order of elements is important. Using this variable-assignment method of string concatenation, you may actually find that the answer that gets returned doesn't have all the values in it, particularly if you want the substrings put in a particular order. Consider the following, which on my machine only returns ',Accessories', when I wanted it to return ',Bikes,Clothing,Components,Accessories':
DECLARE #categories varchar(200)
SET #categories = NULL
SELECT #categories = COALESCE(#categories + ',','') + Name
FROM Production.ProductCategory
ORDER BY LEN(Name)
SELECT #categories
Far better is to use a method which does take order into consideration, and which has been included in SQL2005 specifically for the purpose of string concatenation - FOR XML PATH('')
SELECT ',' + Name
FROM Production.ProductCategory
ORDER BY LEN(Name)
FOR XML PATH('')
In the post I made recently comparing GROUP BY and DISTINCT when using subqueries, I demonstrated the use of FOR XML PATH(''). Have a look at this and you'll see how it works in a subquery. The 'STUFF' function is only there to remove the leading comma.
USE tempdb;
GO
CREATE TABLE t1 (id INT, NAME VARCHAR(MAX));
INSERT t1 values (1,'Jamie');
INSERT t1 values (1,'Joe');
INSERT t1 values (1,'John');
INSERT t1 values (2,'Sai');
INSERT t1 values (2,'Sam');
GO
select
id,
stuff((
select ',' + t.[name]
from t1 t
where t.id = t1.id
order by t.[name]
for xml path('')
),1,1,'') as name_csv
from t1
group by id
;
FOR XML PATH is one of the only situations in which you can use ORDER BY in a subquery. The other is TOP. And when you use an unnamed column and FOR XML PATH(''), you will get a straight concatenation, with no XML tags. This does mean that the strings will be HTML Encoded, so if you're concatenating strings which may have the < character (etc), then you should maybe fix that up afterwards, but either way, this is still the best way of concatenating strings in SQL Server 2005.
building on mwigdahls answer. if you also need to do grouping here is how to get it to look like
group, csv
'group1', 'paul, john'
'group2', 'mary'
--drop table #user
create table #user (groupName varchar(25), username varchar(25))
insert into #user (groupname, username) values ('apostles', 'Paul')
insert into #user (groupname, username) values ('apostles', 'John')
insert into #user (groupname, username) values ('family','Mary')
select
g1.groupname
, stuff((
select ', ' + g.username
from #user g
where g.groupName = g1.groupname
order by g.username
for xml path('')
),1,2,'') as name_csv
from #user g1
group by g1.groupname
You can use this query to do the above task:
DECLARE #test NVARCHAR(max)
SELECT #test = COALESCE(#test + ',', '') + field2 FROM #test
SELECT field2 = #test
For detail and step by step explanation visit the following link
http://oops-solution.blogspot.com/2011/11/sql-server-convert-table-column-data.html
DECLARE #EmployeeList varchar(100)
SELECT #EmployeeList = COALESCE(#EmployeeList + ', ', '') +
CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1
SELECT #EmployeeList
source:
http://www.sqlteam.com/article/using-coalesce-to-build-comma-delimited-string
In SQLite this is simpler. I think there are similar implementations for MySQL, MSSql and Orable
CREATE TABLE Beatles (id integer, name string );
INSERT INTO Beatles VALUES (1, "Paul");
INSERT INTO Beatles VALUES (2, "John");
INSERT INTO Beatles VALUES (3, "Ringo");
INSERT INTO Beatles VALUES (4, "George");
SELECT GROUP_CONCAT(name, ',') FROM Beatles;
you can use stuff() to convert rows as comma separated values
select
EmployeeID,
stuff((
SELECT ',' + FPProjectMaster.GroupName
FROM FPProjectInfo AS t INNER JOIN
FPProjectMaster ON t.ProjectID = FPProjectMaster.ProjectID
WHERE (t.EmployeeID = FPProjectInfo.EmployeeID)
And t.STatusID = 1
ORDER BY t.ProjectID
for xml path('')
),1,1,'') as name_csv
from FPProjectInfo
group by EmployeeID;
Thanks #AlexKuznetsov for the reference to get this answer.
A clean and flexible solution in MS SQL Server 2005/2008 is to create a CLR Agregate function.
You'll find quite a few articles (with code) on google.
It looks like this article walks you through the whole process using C#.
If you're executing this through PHP, what about this?
$hQuery = mysql_query("SELECT * FROM users");
while($hRow = mysql_fetch_array($hQuery)) {
$hOut .= $hRow['username'] . ", ";
}
$hOut = substr($hOut, 0, strlen($hOut) - 1);
echo $hOut;