I am trying to trigger a report to run with "select all" checked for a field FiscalYearId, which is a string type. I can successfully pass one string such as "2" and the report will find it. However, when I try to pass "select all" or "2,3,4", the multi-check field does not pick up on this.
Here is part of the stored procedure from the report:
ALTER PROCEDURE [dbo].[...]
#FiscalYearId varchar (100) = null ,
...
select ...
where ...
and (#FiscalYearID IS NULL OR p.FiscalYearId IN (SELECT * FROM SPLIT(#FiscalYearID, ',')))
my c# code which triggers the report to pop up in a radwindow is:
`string years = "2,3,4";
newWindow.NavigateUrl = "../Reporting/SingleReport.aspx?Report=AdHocSourcingReport&VendorID="
+ vendorId + "&VendorReport=true" + "&FiscalYearId="+years;`
Currently, the vendorId string and VendorReport boolean pull through successfully, it is the string separated by commas that is not populating when the report is run. I initially tried to send a "select all", which is what I want.. Any help is greatly appreciated!!
This is how I've handled splitting comma delimited strings in the past:
CREATE FUNCTION
[dbo].[GetItemTable]
(
#Items VARCHAR(1000)
)
RETURNS
#ItemTable TABLE
(
RowID INT IDENTITY(1,1) PRIMARY KEY,
item VARCHAR(30)
)
AS
BEGIN
DECLARE #ProcessItems VARCHAR(1000)
DECLARE #CurrentItem VARCHAR(30)
SET #ProcessItems = REPLACE(#Items, '''', '')
IF SUBSTRING(#ProcessItems, LEN(#ProcessItems), 1) ','
SET #ProcessItems = #ProcessItems + ','
WHILE CHARINDEX(',', #ProcessItems) > 0
BEGIN
SET #CurrentItem = LTRIM(CAST(SUBSTRING(#ProcessItems, 0, CHARINDEX(',', #ProcessItems)) AS VARCHAR(30)))
INSERT INTO
#ItemTable
(
item
)
VALUES
(
#CurrentItem
)
SET #ProcessItems = SUBSTRING(#ProcessItems, CHARINDEX(',', #ProcessItems) + 1, LEN(#ProcessItems))
END -- While Schedule
RETURN
END
Obviously, you can change the current item size to whatever you happen to need it to be.
Then just use it like this:
WHERE (p.FiscalYearId IN(SELECT item FROM dbo.GetItemTable(#FiscalYearID)))
I remember doing something similar couple years ago and having same kinds of problem with the list.
Can you try this...
ALTER PROCEDURE [dbo].[...] #FiscalYearId varchar (100) = null ,
... select... where... and
(#FiscalYearID IS NULL OR p.FiscalYearId IN (#FiscalYearID))
Also, if you are sending "Select all" string, you might need to have a condition in your procedure to check that and change the query to "Select id from fiscalyeartable"
Related
I have basic procedure which basically looks like following:
create procedure zsp_selectallupceans_list
(#UPCList nvarchar(4000),
#EANList nvarchar(4000))
as
select *
from data as dd
where dd.UPC in (--myUPC list) or dd.EAN in (--myEAN list)
This is the basic idea. Now I need to somehow split this string that I passed from my C# application and it would look like following for the UPC and EAN List:
where dd.UPC in ('123','456','567') or dd.EAN in('1234','5542','412')
The UPCList parameter that is passed from C# application looks like:
'123,456,567' and eanlist: '1234,5542,412'
I have found a method which looks like this:
CREATE FUNCTION dbo.splitstring
(#stringToSplit VARCHAR(MAX))
RETURNS
#returnList TABLE ([Name] [NVARCHAR](500))
AS
BEGIN
DECLARE #name NVARCHAR(255)
DECLARE #pos INT
WHILE CHARINDEX(',', #stringToSplit) > 0
BEGIN
SELECT #pos = CHARINDEX(',', #stringToSplit)
SELECT #name = SUBSTRING(#stringToSplit, 1, #pos-1)
INSERT INTO #returnList
SELECT #name
SELECT #stringToSplit = SUBSTRING(#stringToSplit, #pos+1, LEN(#stringToSplit)-#pos)
END
INSERT INTO #returnList
SELECT #stringToSplit
RETURN
END
And the usage of this function is like following:
SELECT * FROM dbo.splitstring('91,12,65,78,56,789')
where the output is these numbers where they are split and output as a result.
Now I just need to somehow combine all this so that I can form a proper where statement based on passed parameter UPCList and EANList
Can someone help me out with this?
Updating your stored proc as below should do the trick:
create procedure zsp_selectallupceans_list
(
#UPCList nvarchar(4000),
#EANList nvarchar(4000)
)
as
select *
from data as dd
where dd.UPC in (SELECT * FROM dbo.SplitString(#UPCList)) OR
dd.EAN in (SELECT * FROM dbo.SplitString(#EANList))
You pretty much have the answer:
Compile and save the splitstring function and then your where clause will look like the following:
where dd.UPC in (Select Name From splitstring(--myUpcList)) or dd.EAN in (Select Name from splitstring(--myEanList)
Here is an XML based function for string splitting, this method is much faster than the SUBSTRING method you already found. It is also recommended to use EXISTS instead of IN for performance improvement also, see here for more information on this.
CREATE FUNCTION [dbo].[SplitString]
(
#string nvarchar(max),
#delimiter nvarchar(5)
) RETURNS #t TABLE
(
val nvarchar(500)
)
AS
BEGIN
declare #xml xml
set #xml = N'<root><r>' + replace(#string,#delimiter,'</r><r>') + '</r></root>'
insert into #t(val)
select
r.value('.','varchar(500)') as item
from #xml.nodes('//root/r') as records(r)
RETURN
END
To use:
SELECT *
FROM data t
WHERE EXISTS (SELECT 1 FROM dbo.SplitString(#UPCList,',') S1 WHERE t.UPC=S1.val)
OR EXISTS (SELECT 1 FROM dbo.SplitString(#EANList,',') S2 WHERE t.EAN=S2.val)
ALTER PROCEDURE [dbo].[ProcTeamInfoById]
(#id INT,
#txtName VARCHAR(50),
#phone VARCHAR(100),
#contactname VARCHAR(100),
#address VARCHAR(300),
#email VARCHAR(100),
#captain VARCHAR(100),
#requirements VARCHAR(50))
AS
BEGIN
IF #id = -1
BEGIN
DECLARE #teamID VARCHAR(MAX);
INSERT INTO TeamDetails(TeamName, Phone, ContactName, Address, Email, captain)
VALUES (#txtName, #phone, #contactname, #address, #email, #captain)
SET #teamID = SCOPE_IDENTITY();
// Here now I need to add to different table...
// checkbox checked values
INSERT INTO teamrequirements (teamid, requirement, value)
VALUES (#teamID, #requirements, 1)
// Here I am getting 1, bats, Gloves, 1
END
ELSE
UPDATE TeamDetails
SET TeamName = #txtName, Phone = #phone,
ContactName = #contactname,
Address = #address, Email = #email,
WHERE TeamId = #id
END
I need like this how to modify stored procedure
1, bats,gloves,1
I need to insert as
1 bats 1
2 gloves1
If I need to update the above it should be like
1 bats 1
If I updating with no values it should be like
1 '' ''
My stored procedure inserts into two tables. While adding into teamrequirements table, I need to split one column value into multiple columns where I commented. I need to modify the stored procedure to insert into multiple columns and records
in the teamrequirements table.
How to do it?
While adding a team is added into the teamdetails table, and I have checkbox like Requirements if I check that I can select another two checkboxes, when both checkboxes are checked, two records to be inserted in teamrequirements, example , i wil have teamid, requirement, value...example 1,bats,Gloves,1 this should insert as 2 records Like
12,1 bat , 1 // 12 is record id in teamrequirements
13,1,Gloves , 1 // 13 is record id in teamrequirements
Please help...
What if it is Update in the same procedure ..
update teamrequirements set requirement= #reuirement , value = 1 where teamid = #id in this case , if i add those two records bats gloves in database i am adding records , what if i need to clear those added records using update statement in the same procedure
You can use any of the split function over the internet or create your own and use it. Below code has been written according to split function in FnSplitString.
You created a split function in your database. This function will return 1 or more values from your string provided. This is your #requirements variable.
IF(LEN(#requirements) > 0)
BEGIN
INSERT INTO teamrequirements (teamid, requirement, value)
SELECT #teamID, splitdata, '1' FROM dbo.[fnSplitString](#requirements,',')
END
ELSE
BEGIN
INSERT INTO teamrequirements (teamid, requirement, value)
VALUES (#teamID, '', '')
END
SQL 2016:
JSON support is there now. So, you can pass string as json and take 2 values into key value table, and insert it directly. No need to split.
FOR UPDATE:
You can take this split string data in a table variable. Update data from table variable as source into main table, with a JOIN condition.
DECLARE #id INT = 40
DECLARE #data TABLE
(
Id INT,
Requirement VARCHAR(50),
Value INT
)
DECLARE #requirements VARCHAR(50) = 'bat,gloves,ball'
INSERT INTO #data
SELECT #id, splitdata, 1 FROM dbo.[fnSplitString](#requirements,',')
SELECT * FROM #data
-- SOMETHING LIKE THIS CAN BE YOUR UPDATE QUERY
UPDATE a SET
value = b.Value
FROM teamrequirements a INNER JOIN #data b ON a.id = b.Id
and a.requirement = b.Requirement
MERGE SAMPLE:
MERGE teamrequirements AS TARGET
USING #data AS SOURCE
ON TARGET.id = SOURCE.Id AND TARGET.requirement = SOURCE.Requirement
--When records are matched, update
--the records if there is any change
WHEN MATCHED THEN
UPDATE SET TARGET.value = SOURCE.Value
--When no records are matched, insert
--the incoming records from source
--table to target table
WHEN NOT MATCHED BY TARGET THEN
INSERT (teamid, requirement, value)
VALUES (SOURCE.Id, SOURCE.Requirement, SOURCE.Value);
First, it would be better to use table valued parameters for this.
Without that, you can split the string (this demo uses delimitedsplit8k by Jeff Moden) , and you could use merge to handle changes. It makes sense to move this into its own procedure and call that procedure from your current one.
TL;DR: rextester demo: http://rextester.com/PVX88970
The TeamRequirements_Merge procedure:
create procedure dbo.TeamRequirements_Merge (
#TeamId int
, #requirements varchar(8000)
) as
begin;
set nocount, xact_abort on;
/* it would be much better to use table valued parameters for this */
;with t as (
select TeamId, Requirement, Value
from TeamRequirements
where TeamId = #TeamId
)
, s as (
select
TeamId = #TeamId
, Requirement = coalesce(s.item,'') -- since you want blanks
, Value = 1
from dbo.[delimitedsplit8K](#requirements,',') s
)
merge into t with (holdlock)
using s
on t.TeamId = s.TeamId
and t.Requirement = s.Requirement
when matched and t.value <> s.value
then update set t.value = s.value
when not matched by target
then insert (TeamId, Requirement, Value)
values (s.TeamId, s.Requirement, s.Value)
when not matched by source
then delete
--output $Action, inserted.*, deleted.* /* for testing */
;
end;
go
The revised ProcTeamInfoById procedure:
create procedure [dbo].[ProcTeamInfoById] (
#id int
, #txtName varchar(50)
, #phone varchar(100)
, #contactname varchar(100)
, #address varchar(300)
, #email varchar(100)
, #captain varchar(100)
, #requirements varchar(8000)
) as
begin;
if #id = -1
begin;
insert into TeamDetails(TeamName, Phone, ContactName, Address, Email, captain)
values (#txtName, #phone, #contactname, #address, #email, #captain);
set #id = scope_identity();
end;
else
begin;
update TeamDetails
set TeamName = #txtName, Phone = #phone,
ContactName = #contactname,
Address = #address, Email = #email
where TeamId = #id;
end;
exec dbo.TeamRequirements_Merge #id, #requirements;
end;
go
splitting strings reference:
Tally OH! An Improved SQL 8K “CSV Splitter” Function - Jeff Moden
Splitting Strings : A Follow-Up - Aaron Bertrand
Split strings the right way – or the next best way - Aaron Bertrand
string_split() in SQL Server 2016 : Follow-Up #1 - Aaron Bertrand
Ordinal workaround for **string_split()** - Solomon Rutzky
merge reference:
Use Caution with SQL Server''s MERGE Statement - Aaron Bertrand
UPSERT Race Condition With Merge - Dan Guzman
An Interesting MERGE Bug - Paul White
Can I optimize this merge statement - Aaron Bertrand
If you are using indexed views and MERGE, please read this! - Aaron Bertrand
The Case of the Blocking Merge Statement (LCK_M_RS_U locks) - Kendra Little
Writing t-sql merge statements the right way - David Stein
Again, it would be better to use table valued parameters for this:
Table Valued Parameters reference:
Table-Valued Parameters - msdn
User-Defined Table Types - msdn
SQL Server 2008 Table-Valued Parameters and C# Custom Iterators: A Match Made In Heaven! - Leonard Lobel
Table Value Parameter Use With C# - Jignesh Trivedi
Using Table-Valued Parameters in SQL Server and .NET - Erland Sommarskog
Maximizing Performance with Table-Valued Parameters - Dan Guzman
Maximizing throughput with tvp - sqlcat
How to use TVPs with Entity Framework 4.1 and CodeFirst
I have a C# app that passes in the following data:
datasetID = 10;
userID = 1;
varnames = "'ACT97','ACTCHNG','ACTQTR2','ACTSCOR2'";
The stored procedure is:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[s_LockCheck]
-- Add the parameters for the stored procedure here
#varNames VARCHAR(max),
#datasetID INT,
#userID INT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
SELECT COUNT(*) as locked FROM VarLocks WHERE var_name IN (#varNames) AND dataset_id = #datasetID AND user_id != #userID AND is_locked = 1
END
But when I call it like so, it is returning a count of 0 when it should be higher than that:
exec s_LockCheck "'ACT97','ACTCHNG','ACTQTR2','ACTSCOR2'", 88, 14
Each ACTXXX above is a varname from the column, var_name.
Why isn't it doing the IN Clause correctly?
There are several ways to accomplish this:
Dynamic SQL, as pointed out in this article: http://asheej.blogspot.com/2012/04/how-to-use-ms-sql-in-clause-with.html
Specify each item in variables (this can get quite ugly if you have a lot of 'em):
#var1 varchar(20),
#var2 varchar(20),
#var3 varchar(20)
Write a split function to turn the string into a table variable, there are many of them out there. This one is my personal favorite: http://dataeducation.com/faster-more-scalable-sqlclr-string-splitting/
Use a Table Value Parameter (2008): http://www.techrepublic.com/blog/datacenter/passing-table-valued-parameters-in-sql-server-2008/168
Here's a little trick using CHARINDEX (note that this approach is Non-Sargable):
Your string is like so: 'abc,def'
Using CHARINDEX, you pad both the search string and value you want to find within the search string with your delimeter. So using my little example, the string would become ',abc,def,' Notice the extra commas at the beginning and end. Then do the same thing to the field data. If you have commas in your data, you'll have to swap out the delimeter to something else, like char(2), or semi-colons, or whatever.
Then to perform the search:
WHERE CHARINDEX ( ',' + expressionToFind + ',' , ',' + expressionToSearch ',') > 0
The delimeter padding keeps the search from finding "abcabc" but will find "abc", exact match.
If you're using 2005, I'd grab a really fast split function so you can avoid using dynamic SQL.
Your query should use STRING_SPLIT for IN, like this:
SELECT COUNT(*) as locked FROM VarLocks
WHERE var_name
IN (SELECT value FROM STRING_SPLIT(#varNames, ','))
AND dataset_id = #datasetID
AND user_id != #userID
AND is_locked = 1
You had wrong syntax for IN operator: IN (#varNames)
and you needed IN (SELECT value FROM STRING_SPLIT(#varNames, ',')).
STRING_SPLIT performs string splitting according to delimiter, which is comma in your case.
pass comma separated string from c#
sql
WHERE Location IN (SELECT value FROM STRING_SPLIT(#SearchLocation,'|'))
I am retrieving values from listbox and formatting them in string as
if (lbRaisedByLogin.SelectedIndex != -1)
{
foreach (ListItem item in lbRaisedByLogin.Items)
{
if (item.Selected == true)
{
sb.AppendFormat("{0},", item.Value);
}
}
searchCase.raisedByLogin = sb.ToString().TrimEnd(Convert.ToChar(","));
sb.Length = 0;
}
I am passing these strings to store procedure as parameter (Datatype-- Varchar(Max))
in stored procedure I am comparing these values like
SELECT * FROM AUS_CID_Cases
WHERE
AddedBy IN ( #raisedByLogin )
Where #raisedByLogin is one of the parameter i passed. It has values like #raisedByLogin="4,2,1"
AddedBy has datatype bigint.
When I run code I get error as "Error converting data type varchar to bigint.".. I understand it is because AddedBy column has datatype bigint. I can not change that datatype.
However when i cast AddedBy like
SELECT * FROM AUS_CID_Cases
WHERE
CAST(AddedBy as VARCHAR) IN ( #raisedByLogin )
I dont get error, but nothing is selected i.e I dont get any result from select statement.
What can I do?
First create this view
CREATE FUNCTION [dbo].[Split](#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (items varchar(8000))
as
begin
declare #idx int
declare #slice varchar(8000)
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
insert into #temptable(Items) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
then change the query to this and try,
SELECT * FROM AUS_CID_Cases
WHERE
CAST(AddedBy as VARCHAR) IN ( select * from split(#raisedByLogin,',') )
found above Function here, and managed to solve this issue sometime back...
try to build SQL select query inside stored procedure and execute after that.
DECLARE #raisedByLogin varchar(600)
SET #SQL =
'SELECT * FROM AUS_CID_Cases
WHERE
AddedBy IN (' + #raisedByLogin + ')'
EXEC(#SQL)
check How to pass a list of values or array to SQL Server stored procedure? for more information
I've had a search round the internet and cannot find anything that directly matches what I'm after....
I have a stored procedure that returns a fixed set of columns (let's say ColumnA, ColumnB and ColumnC) and then additionally returns an indeterminate number / signature of additional columns (maybe ColumnD, ColumnE and ColumnF, or ColumnF, ColumnP, ColumnT and ColumnW).
The dynamic part of the query is determined by an Id param to the proc.
Unfortunately I am not in control of the schema and it has been poorly designed to have a very large number of unrelated columns added to the end (and they keep adding them), rather than having an additional table(s) to store this effectively.
As a result, I am unable to return a determinate set of columns at compile time, so LINQ to SQL cannot determine the return type of the stored procedure.
Do I have any other options, or ways I can get around this? Here's an example of what I am doing below. Can I re-write this to work with LINQ to SQL? I am writing the application with C# and SQL Server 2008 if that helps.
Thanks.
CREATE PROCEDURE [Foo].[GetBar]
(
#Id INT,
#FooVar VARCHAR(50),
#BarVar DATE
)
AS
BEGIN
CREATE TABLE #TempTbl
(
[ColumnName] VARCHAR(50)
)
INSERT #TempTbl EXEC [Foo].GetColumnNames #Id
DECLARE #ColumnNameList NVARCHAR(max)
SET #ColumnNameList = ''
SELECT #ColumnNameList = COALESCE(#ColumnNameList + '],[', '') + ColumnName FROM #TempTbl
DROP TABLE #TempTbl
SELECT #ColumnNameList = #ColumnNameList + ']'
SELECT #ColumnNameList = SUBSTRING(#ColumnNameList, 3, LEN(#ColumnNameList) )
DECLARE #FixedColumns VARCHAR(200)
DECLARE #SelectQuery NVARCHAR(max)
DECLARE #WhereQuery VARCHAR (100)
DECLARE #FullQuery NVARCHAR(max)
DECLARE #ParamaterDef nvarchar (100)
DECLARE #Foo VARCHAR(50)
DECLARE #Bar DATE
SET #FixedColumns = N'[ColumnA], [ColumnB], [ColumnC], '
SET #SelectQuery = N'SELECT ' + #FixedColumns + #ColumnNameList + N' FROM [Foo].[FooBar] '
SET #WhereQuery = N'WHERE [Foo] = #Foo AND [Bar] = #Bar'
SET #FullQuery = #SelectQuery + #WhereQuery
SET #ParamaterDef = N'#Foo VARCHAR(50), #Bar DATE'
EXECUTE sp_executesql #FullQuery, #ParamaterDef, #Foo = #FooVar, #Bar = #BarVar
END
Can you not just use a SQL Data Adapter that fills a DataSet? You could then use LINQ to DataSet and perform all of your LINQ operations:
DataTable yourDataTable = ds.Tables["TableName"];
var query =
from yourDataTable in yourDataTable.AsEnumerable()
select new
{
NewField = yourDataTable.Field<int>("ColumnName"),
NewField2 = yourDataTable.Field<string>("ColumnName2"),
};
MSDN (LINQ to DataSet)
MSDN (Single table queries using LINQ to DataSet