Finding row until condition is met - sql

This is my table:
PackingNr
SerienNr
PN185971
PN185972
PN185972
PN185974
PN185974
PN185978
PN185978
R005478
PN185968
R000547
PN185725
R004987
As an input I get PackingNr and I need to select SerienNr which is like Rxxxxx not PNxxxxx.
So for example, if I have input PN175971, I need to get SerienNr = R005478.
How can I do this inside of select query? I tried CASE but this won't work as I don't know how many times I have to go again.
My select query is selecting also other columns from different tables.
SELECT
... ,
CASE
WHEN PSPD.SerienNr LIKE '%PN%'
THEN
(SELECT SerienNr FROM PSAPacking_Det
WHERE PSAPacking_Det.PackingNr = PSPD.SerienNr)
ELSE PSPD.SerienNr
END AS SerienNr
...
FROM
PSAPacking PSPD
JOIN
...
WHERE
PSPD.PackingNr = 'PN185971'

You need a recursive CTE. Something like this:
WITH cte AS (
SELECT t.PackingNr, t.SerienNr
FROM YourTable t
WHERE t..PackingNr = 'YourValueHere'
UNION ALL
SELECT t.PackingNr, t.SerienNr
FROM YourTable t
JOIN cte ON cte.SerienNr = t.PackingNr
)
SELECT TOP (1)
*
FROM cte
WHERE cte.SerienNr LIKE 'R%';

try this
declare #var2 varchar(max) = 'PN185971' --PUT YOUR INPUT HERE
declare #var1 varchar(max);
while(#var2 not like 'R%')
begin
set #var1 = #var2
set #var2 = (select max(SerienNr) from PSAPacking where PackingNr = #var1)
end
select #var2
if it doesn't find the value starting with R it returns null

Related

I am having the error with a Subquery returning more than one value. How do I reduce to one?

At the very end of the Stored procedure a SELECT statement is made to display the contents of the Table including function that will simultaneously populate fields in the table.
Here is the Select Statement:
IF #type = 'SH'
SELECT DISTINCT *
FROM #History
ORDER BY 1, 2, 3, 4, 5
ELSE
SELECT DISTINCT AmhazName
,Activity
,ServiceName
,Sarid
,PerformedDate
,UserRole
,Details
,dbo.ufn_SarHistoryActionText(sarid, status, performeddate) AS [ActionText]
,FullName
,CategoryDescription
,StatusDescription
,ActionPerformed
,Case
when Details like '%ProjManagerId%'
Then dbo.ufn_GetUserForHistoryReport (PerformedDate, SarId, '%ProjManagerId%')
Else
--when Details like '%UserId%'
dbo.ufn_GetUserForHistoryReport (PerformedDate, SarId, '%UserId%')
--(select 'no user') as [AssignedUser]
End as [AssignedUser]
--,dbo.ufn_GetPMForHistoryReport(PerformedDate, SarId) as [AssignedUser]
FROM #history
ORDER BY 1, 2, 3, 4, 5
DROP TABLE #Historyw
Here is the function I believe is causing problems:
ALTER FUNCTION [dbo].[ufn_SarHistoryActionText]
(
-- Add the parameters for the function here
#sarID int
, #status varchar(6)
, #statusDate datetime
)
RETURNS varchar(100)
AS
BEGIN
-- Declare the return variable here
DECLARE #Result varchar(100)
set #Result = (
SELECT C.ActionText
from LuStatusChange as C
WHERE C.FromStatus = dbo.ufn_SarHistoryPriorStatus(#sarID,#status,#statusDate)
AND C.ToStatus = #status
)
-- Return the result of the function
RETURN #Result
END
GO
As I debug and walk through loads of values, I haven't come across anything that resulted in multiple values. maybe I'm missing something.
Add TOP 1 in the select inside the function:
SELECT TOP 1 C.ActionText
Can you replace
set #Result = (
SELECT C.ActionText
from LuStatusChange as C
WHERE C.FromStatus = dbo.ufn_SarHistoryPriorStatus(#sarID,#status,#statusDate)
AND C.ToStatus = #status
)
as below:
#Result ***IN*** (
SELECT C.ActionText
from LuStatusChange as C
WHERE C.FromStatus = dbo.ufn_SarHistoryPriorStatus(#sarID,#status,#statusDate)
AND C.ToStatus = #status
)
If functionally your query should not written more than 1 row, something is wrong with your query.

Using "IN" operator in a dynamic query

i've been searching SO for a while and found nothing related to this.
We use heavily the dynamic approach for most of our queries like this:
Declare #ContactId VarChar(8000)
Select #ContactId = '1'
Select *
From Person.Contact
Where 1 = 1 And
Case When Len(Ltrim(Rtrim(#ContactId))) = 0 Then 1 Else ContactID End =
Case When Len(Ltrim(Rtrim(#ContactId))) = 0 Then 1 Else #ContactId End
This way the query gets filtered dynamically if there's a value on the parameter
But the problem comes when trying the same stuff with several IDs like so:
Declare #ContactId VarChar(8000)
Select #ContactId = '1,2,3'
Select *
From Person.Contact
Where 1 = 1 And
Case When Len(Ltrim(Rtrim(#ContactId))) = 0 Then 1 Else ContactID End In (
Select Case When Len(Ltrim(Rtrim(#ContactId))) = 0 Then 1 Else ( Select id From dbo.SplitString(#ContactId,',') ) End )
Sql throws an error "Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression."
that's totally normal and expected, my question is:
Is there a way to dynamically do this kind of filtering ?
The solution we use is this:
Declare #Table Table(
Col1 Int,
Col2 Int,
Col3 Int
)
Insert #Table
Select Col1, Col2, Col3
From Person.Contact
Where [many filters except the in clause filters]
If Len(Ltrim(RTrim(#ContactId))) > 0
Select *
From #Table
Where ContactId In ( Select Id From dbo.SplitString(#ContactId, ',') )
Else
Select *
From #Table
But it's not an option when the query is massive and feeding a table variable is overkill for this. Hope i made my point and someone is kind enough to help me find a solution to this.
PS: Using sp_ExecuteSql is not an option in this scenario either, sorry.
How you should do this is with a table parameter.
But if you want to persist in this approach.
Declare #ContactId VarChar(8000)
Select #ContactId = '1,2,3'
Select *
From Person.Contact
where ',' + #contactID + ',' like '%,'+convert(varchar(50),contactid)+',%'
Try this
Select *
From Person.Contact
Where (
len(#contactid) > 0 AND
ContactID IN (Select id From dbo.SplitString(#ContactId,',')))
or 1 = 1

Select with IN and Like

I have a very interesting problem. I have an SSRS report with a multiple select drop down.
The drop down allows to select more than one value, or all values.
All values is not the problem.
The problem is 1 or the combination of more than 1 option
When I select in the drop down 'AAA' it should return 3 values: 'AAA','AAA 1','AAA 2'
Right now is only returning 1 value.
QUESTION:
How can make the IN statement work like a LIKE?
The Drop down select
SELECT '(All)' AS team, '(All)' AS Descr
UNION ALL
SELECT 'AAA' , 'AAA'
UNION ALL
SELECT 'BBB' , 'BBB'
Table Mytable
ColumnA Varchar(5)
Values for ColumnA
'AAA'
'AAA 1'
'AAA 2'
'BBB'
'BBB 1'
'BBB 2'
SELECT * FROM Mytable
WHERE ColumnA IN (SELECT * FROM SplitListString(#Team, ',')))
Split function
CREATE FUNCTION [dbo].[SplitListString]
(#InputString NVARCHAR(max), #SplitChar CHAR(1))
RETURNS #ValuesList TABLE
(
param NVARCHAR(MAX)
)
AS
BEGIN
DECLARE #ListValue NVARCHAR(max)
DECLARE #TmpString NVARCHAR(max)
DECLARE #PosSeparator INT
DECLARE #EndValues BIT
SET #TmpString = LTRIM(RTRIM(#InputString));
SET #EndValues = 0
WHILE (#EndValues = 0) BEGIN
SET #PosSeparator = CHARINDEX(#SplitChar, #TmpString)
IF (#PosSeparator) > 1 BEGIN
SELECT #ListValue = LTRIM(RTRIM(SUBSTRING(#TmpString, 1, #PosSeparator -1 )))
END
ELSE BEGIN
SELECT #ListValue = LTRIM(RTRIM(#TmpString))
SET #EndValues = 1
END
IF LEN(#ListValue) > 0 BEGIN
INSERT INTO #ValuesList
SELECT #ListValue
END
SET #TmpString = LTRIM(RTRIM(SUBSTRING(#TmpString, #PosSeparator + 1, LEN(#TmpString) - #PosSeparator)))
END
RETURN
END
You can't. But, you can make the like work like the like:
select *
from mytable t join
SplitListString(#Team, ',') s
on t.ColumnA like '%'+s.param+'%'
That is, move the split list to an explicit join. Replace with the actual column name returned by the function, and use the like function.
Or, if you prefer:
select *
from mytable t cross join
SplitListString(#Team, ',') s
where t.ColumnA like '%'+s.param+'%'
The two versions are equivalent and should produce the same execution plan.
Better approach would be to have a TeamsTable (teamID, teamName, ...) and teamMembersTable (teamMemberID, teamID, teamMemberDetails, ...).
Then you an build your dropdown list as
SELECT ... FROM TeamsTable ...;
and
SELECT ... FROM teamMembersTable WHERE teamID IN (valueFromYourDropDown);
Or you can just store your teamID or teamName (or both) in your (equivalent of) teamMembersTable
You're not going to get IN to work the same as LIKE without a lot of work. You could do something like this though (and it would be nice to see some of your actual data though so we could give better solutions):
SELECT *
FROM table
WHERE LEFT(field,3) IN #Parameter
If you'd like better performance, create a code field on your table and update it like this:
UPDATE table
SET codeField = LEFT(field,3)
Then just add an index on that field and run this query to get your results:
SELECT *
FROM table
WHERE codeField IN #Parameter

top count for a SQL query

I want to have a variable for selecting top rows. I can select top rows based on a variable. However I want to select all rows if the variable is not supplied.
Currently I'm using this query:
DECLARE #TOPCOUNT int;
SET #TOPCOUNT=10;
SELECT TOP(#TOPCOUNT) * FROM TABLE1
Update:
The original query is very lengthy and complex, so I don't to rewrite the entire query without top count in else clause.
I don't want to use dynamic query because of its repercussions.
Something like this:
DECLARE #TOPCOUNT int;
--SET #TOPCOUNT=10;
IF #TOPCOUNT IS NULL
SELECT * FROM TABLE1
ELSE
SELECT TOP(#TOPCOUNT) * FROM TABLE1
Added after above UPDATE - if this is a parameter of a Stored Procedure then just provide a default for #TOPCOUNT:
#TOPCOUNT INT = 2147483647 --max size of INT
Something like this will help. Just init your #TOPCOUNT with -1 if you want all rows.
IF #TOPCOUNT = -1 BEGIN
SELECT * FROM TABLE1
END
ELSE BEGIN
SELECT TOP(#TOPCOUNT) * FROM TABLE1
END
IF #TOPCOUNT IS NULL SET #TOPCOUNT=2147483647

How can I use if statement after a CTE (SQL Server 2005)

Last night I was writing a simple T-SQL program something like this
DECLARE #ROLEID AS INT
SELECT #ROLEID = [ROLE ID] FROM TBLROLE
;WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
IF (#ROLEID = 1)
BEGIN
//SOMECODE
END
ELSE IF(#ROLEID = 2)
BEGIN
//SOMECODE
END
ELSE
BEGIN
//SOMECODE
END
I found after compilation that it is throwing error something like "Incorrect statement near if"
What is wrong?
However, I did that by using some other way. But I wanted to know why it did not work!
Common table expressions are defined within the context of a single statement:
WITH cte_name AS (
<cte definition>)
<statement that uses cte>;
So you can do something like:
WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
SELECT * FROM CTE;
or
WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
UPDATE CTE
SET somefield = somevalue
WHERE id = somekey;
A CTE must be followed by a single
SELECT, INSERT, UPDATE, MERGE, or
DELETE statement that references some
or all the CTE columns. A CTE can also
be specified in a CREATE VIEW
statement as part of the defining
SELECT statement of the view
A little late but I can't be the only one bumping into this.
A solution could be to create a temporary table like this:
-- If previous run of this query fails, the temp table will be deleted.
-- Selecting into creates the temp table which fails if it already exists
IF EXISTS(SELECT [name] FROM tempdb.sys.tables WHERE [name] like '#dtBalansOpgesteldGefilterd%') BEGIN
DROP TABLE #temp
END;
;WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
-- Followed by select statement as required
SELECT *
INTO #temp
FROM CTE
IF #awsome = 1
BEGIN
SELECT 'WHATEVERYOUWANT' AS WhateverColumnNameYouWant, *
FROM #temp
END
The closest you'll get is using a UNION ALL to do a crude switched select:
DECLARE #ROLEID AS INT
SELECT #ROLEID = [ROLE ID] FROM TBLROLE
;WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
SELECT
--somecolumns
FROM
CTE
--other stuff too
WHERE
#ROLEID = 1
UNION ALL
SELECT
--somecolumns
FROM
CTE
--other stuff too
WHERE
#ROLEID = 2
UNION ALL
SELECT
--somecolumns
FROM
CTE
--other stuff too
WHERE
#ROLEID = 3
...
UNION ALL
SELECT
--somecolumns
FROM
CTE
--other stuff too
WHERE
#ROLEID = n
Try putting the CTE in the IF. It worked for me.
IF #awsome = 1
BEGIN
;WITH CTE
AS
(
SELECT * FROM SOMETABLE
)
SELECT 'WHATEVERYOUWANT' FROM CTE
END
ELSE IF #awesome = 2
BEGIN
;WITH CTE2
AS
(
SELECT * FROM SOMETABLE
)
SELECT 'WHATEVERYOUWANT' FROM CTE2
END