TSQL: if statement inside a select insert - sql

I have this structure inside a function:
INSERT INTO #TheTable
SELECT DISTINCT
#Number AS Number,
#Name AS Name
FROM MYTABLE
WHERE id = #id
I need to add to this structure the result of executing another function and I need your help to do so.
Below the #Name AS Name, line I should add something like this
IF (dbo.anotherFunction(#id)==1)
#NewVisitor AS NewVisitor
ELSE
#NewVisitor AS NoNewVisitor
How can I translate this into TSQL??
Thanks a million!

Guessing this is what you want...
INSERT INTO #TheTable
SELECT DISTINCT
#Number AS Number,
#Name AS Name,
case when (dbo.anotherFunction(#id)=1) then #NewVisitor else null end as NewVisitor,
case when (dbo.anotherFunction(#id)<>1) then #NewVisitor else null end AS NoNewVisitor
FROM MYTABLE
WHERE id = #id

IF statements aren't available inside of SELECT statements. Instead, you'll want to utilize a CASE.
MSDN Documentation on CASE

This question makes little sense to me (why all the variables, what do the columns mean?), but you can do it this way:
IF (dbo.anotherFunction(#id)==1)
INSERT INTO #TheTable
SELECT DISTINCT
#Number AS Number,
#Name AS Name,
#NewVisitor AS NewVisitor
FROM MYTABLE
WHERE id = #id
ELSE
INSERT INTO #TheTable
SELECT DISTINCT
#Number AS Number,
#Name AS Name,
#NewVisitor AS NoNewVisitor
FROM MYTABLE
WHERE id = #id
Alternatively use two CASE statements to selected NewVisitor and NoNewVisitor.

Related

Complex Conditional Query in Where Clause

In my company, each department has their own statuses for purchase orders. I'm trying to load only the pertinent POs for a specific user's department. I keep getting errors. It seems like it should be correct, though. I initially attempted to use a Case statement, but it appears that SQL can only do a simple return from a case, so I'm now attempting If statements. Current error is Incorrect Syntax near the keyword IF. It looks right to me. It's as if the incorrect syntax is that it is in the IN parentheses.
declare #Dept nvarchar(12);
set #Dept = 'IT'
SELECT *
FROM TBL_ORDERS
WHERE ORD_STATUS IN
(
IF #Dept = 'PURCH'
BEGIN
SELECT distinct * FROM (VALUES ('PurchStat1'), ('PurchStat2'), ('PurchStat3'), ('PurchStat4')) AS X(a)
END
ELSE
IF #Dept = 'ADMIN'
BEGIN
SELECT distinct * FROM (VALUES ('ADStat1')) AS X(a)
END
ELSE
IF #Dept = 'IT'
BEGIN
SELECT distinct * FROM (VALUES ('ADStat1'), ('PurchStat1'), ('PurchStat2'), ('PurchStat3'), ('PurchStat4'), ('ITStat1'), ('ITStat2')) AS X(a)
END
ELSE END
)
There's a conceptual problem to address here first, and then we can look at how to actually do what you want.
select is starting a statement here. Statements end with a semicolon. You can't put statements inside other statements. What you are doing is the same as trying to do something like this in c#:
int i = if (true) 1; else 2;;
You can of course use expressions inside statements:
int i = true ? 1 : 2;
Moreover, select is a declarative statement. You can't do imperative flow of control inside a declarative language construct. You're mixing metaphors, as it were. To understand the declarative/imperative distinction see this question and in particular (in my opinion) this answer.
So the first thing to do is wrap your head around the declarative nature of SQL statements like select. Yes, T-SQL also includes imperative constructs like if and while, but you can't do imperative inside declarative.
You can use conditional expressions (and other expressions) inside a declarative statement:
select name,
case
when name = 'date' then 'this is the date row'
else 'this is not the date row'
end
from sys.types;
In this example the declarative select says what to do with all of the rows returned by the from clause. I don't write a while loop or a for loop in order to instruct the computer to loop over each row and provide instructions inside the loop. The from returns all the rows, and the select declares what I want to do with each of them. The case expression will be evaluated against every row in sys.types.
OK, so what about your specific question? There's many ways to write the code. Here is one way that is very similar to your current structure. First I conditionally (imperatively!) populate a temp table with the statuses I want. Then I declaratively use that temp table as my filter:
create table #statuses
(
statusname varchar(32)
);
declare #dept nvarchar(12) = 'IT';
if (#dept = 'IT')
begin
insert #statuses (statusname) values
('ADStat1'), ('PurchStat1'), ('PurchStat2'), ('PurchStat3'), ('PurchStat4'), ('ITStat1'), ('ITStat2');
end
else if (#dept = 'PURCH')
begin
insert #statuses (statusname) values
('PurchStat1'), ('PurchStat2'), ('PurchStat3'), ('PurchStat4');
end
else if (#dept = 'ADMIN')
begin
insert #statuses (statusname) values
('ADStat1');
end
select *
from tbl_orders
where ord_status in (select statusName from #statuses);
Can I do it without the temp table? Sure. Here's one way:
declare #dept nvarchar(12) = 'IT';
select *
from tbl_orders
where (#dept = 'ADMIN' and ord_status = 'ADStat1')
or (#dept = 'PURCH' and ord_status in ('PurchStat1', 'PurchStat2', 'PurchStat3', 'PurchStat4'))
or (#dept = 'IT' and ord_status in ('ADStat1', 'PurchStat1', 'PurchStat2', 'PurchStat3', 'PurchStat4', 'ITStat1', 'ITStat2'));
Here we evaluate a different in depending on the value of #dept. Clearly only one of them actually needs to be evaluated, and the other two don't really need to be there, depending on which value of #dept is provided. Adding an option (recompile) can be beneficial in cases like this. For more information about option (recompile) look here and here.
If for a reason storing those status/department data in tables is not possible you can use union
declare #Dept nvarchar(12);
set #Dept = 'IT'
SELECT *
FROM TBL_ORDERS
WHERE ORD_STATUS IN
(
SELECT distinct *
FROM (VALUES ('PurchStat1'), ('PurchStat2'), ('PurchStat3'), ('PurchStat4')) AS X(a)
WHERE #Dept ='PURCH'
union all
SELECT distinct *
FROM (VALUES ('ADStat1')) AS X(a)
WHERE #Dept ='ADMIN'
union all
SELECT distinct *
FROM (VALUES ('ADStat1'), ('PurchStat1'), ('PurchStat2'), ('PurchStat3'), ('PurchStat4'), ('ITStat1'), ('ITStat2')) AS X(a)
WHERE #Dept ='IT'
)

Stored procedure to sort one row with other rows places

I would like to add this to a parameterized stored procedure. I have code to sort it like that but it is just a select statement.
SELECT *
FROM [AdventureWorks2014].[Person].[CountryRegion]
ORDER BY
CASE CountryRegionCode
WHEN 'GB' THEN '1'
WHEN 'BR' THEN '2'
ELSE Name
END
GO
In these pictures everything could be clear what I would like to happen. Before and after sort. Thanks!
I would use this personally. to sort by name after the preference sort
CREATE PROCEDURE yourProcedureName
#RegionCode nvarchar(2)
AS
--your select
ORDER BY
CASE CountryRegionCode
WHEN #RegionCode THEN 1
ELSE 2
END,
Name
Another way to do it
CREATE PROCEDURE yourProcedureName #RegionCode nvarchar(2)
AS
SELECT *
FROM [AdventureWorks2014].[Person].[CountryRegion]
WHERE CountryRegionCode = #RegionCode
UNION ALL
SELECT *
FROM [AdventureWorks2014].[Person].[CountryRegion]
WHERE CountryRegionCode = #RegionCode
--Any order by you need
END
GO
And call it using :
EXEC yourProcedureName #RegionCode = 'GB'
This was the result what I needed and what worked to replace one record under the specified parameter record.
ALTER PROCEDURE something
#CountryRegionCode nvarchar(3),
#Name nvarchar(50)
AS
SELECT Name,CountryRegionCode,ModifiedDate FROM [AdventureWorks2014].[Person].[CountryRegion]
ORDER BY
CASE CountryRegionCode
WHEN #CountryRegionCode THEN #Name
ELSE Name
END

SQL Server Stored Procedure Check if Record Exists Before Insert

I am doing a check to see if a record exists before inserting it into a table (and this method seems to work on other stored procedures I am already using) but for this particular stored procedure it is not inserting anything even though the table is empty, why not?
CREATE PROCEDURE spInsertMovieHasTrailer
#movieID int,
#name varchar(50)
AS
BEGIN
SELECT #name = name, #movieID = movieID
FROM MovieHasTrailer
WHERE name = #name and movieID = #movieID
IF #name IS NULL and #movieID IS NULL
BEGIN
INSERT INTO MovieHasTrailer
(
movieID,
name
)
Values (
#movieID,
#name
)
END
END
Executing like this:
execute spInsertMovieHasTrailer 1, 'Test'
I would build this directly into the insert and not use if logic. if introduces race conditions:
INSERT INTO MovieHasTrailer
SELECT movieID, name
FROM (SELECT #movieID as movieID, #name as name) t
WHERE NOT EXISTS (SELECT 1
FROM MovieHasTrailer mht
WHERE mht.MovieId = t.MovieID AND mht.name = t.name
);
Note that this assumes that you need both the id and name to match the movie. I would think the id would be sufficient.
Also, what I would really do is have a unique index on either MovieHasTrailer(MovieId) or MovieHasTrailer(MovieId, Name). Then use a try/catch block if there is an insert error.
your select into variable may returns more than one value and you get error, it's better to use if not exists:
IF NOT EXISTS
(
SELECT name, movieID
FROM MovieHasTrailer
WHERE name = #name and movieID = #movieID
)
BEGIN
INSERT INTO MovieHasTrailer
(
movieID,
name
)
Values (
#movieID,
#name
)
END
The reason you are not doing an insert is the following code will not change the value of #name and #movieID if the query returns no records
SELECT #name = name, #movieID = movieID
FROM MovieHasTrailer
WHERE name = #name and movieID = #movieID
Whatever value for #name and #movieID you are passing into the stored procedure remain unchanged. I assume you are not passing in null values so the IF block is never executed.
You can try this way also you can achieve your goal and it save your time also.
INSERT INTO MovieHasTrailer
SELECT #movieID as movieID, #name as name
except
select MovieId, name
FROM MovieHasTrailer mht
where MovieId = #MoveID
I would do this by standart MERGE statement:
Create table t(id int, name nvarchar(max))
Declare #id int = 1, #name nvarchar(max) = 'Mission imposible'
Merge t using (select #id, #name) as s(id, name)
on t.id = s.id
when not matched then
insert(id, name) values(s.id, s.name);
You can also add WHEN MATCHED THEN UPDATE, WHEN NOT MATCHED BY SOURCE THEN DELETE to this statement.
Fiddle: http://sqlfiddle.com/#!6/c2569/23
try this :
CREATE PROCEDURE spInsertMovieHasTrailer
#movieID int,
#name varchar(50)
AS
BEGIN
declare #rowStatus nvarchar(50)=null
set #rowStatus=(SELECT name FROM MovieHasTrailer WHERE name = #name and movieID = #movieID)
IF (#rowStatus is NULL)
BEGIN
INSERT INTO MovieHasTrailer
(
movieID,
name
)
Values (
#movieID,
#name
)
END
END

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

IF condition in view in SQL Server

Is it possible to have a if condition in VIEWS
eg
CREATE VIEW
as
DECLARE #Count int
SET #Count=-1
select #Count=EmpID from EmployeeDetails where ID=200
IF #Count=-1
BEGIN
SELECT * FROM TEAM1
END
ELSE
BEGIN
SELECT * FROM TEAM1
END
You could try something sneaky with a UNION :
SELECT {fieldlist}
FROM Table1
WHERE EXISTS(SELECT EmpID FROM EmployeeDetails WHERE ID = 200)
UNION ALL
SELECT {fieldlist}
FROM Table2
WHERE NOT EXISTS(SELECT EmpID FROM EmployeeDetails WHERE ID = 200)
This method would require both SELECT statements to return the same set of fields, although their sources might be different.
Views only allow select statements as stated in here
if you need to do if on column values you can use a
SELECT
CASE WHEN COLUMN1 = 1 THEN COLUMNX ELSE COLUMNY END
FROM TABLE1
if your need exceeds this you should create a select from a table valued function instead of a view.
What you need is a simple Procedure
CREATE PROCEDURE DOSOMETHING
(
#ID INT
)
AS
BEGIN
IF #ID > 100
SELECT 1 AS ID,'ME' AS NAME, GETDATE() AS VARIABLEDATECOL, NEWID() AS VARIABLEGUID
ELSE
SELECT 2 AS ID, 'YOU' AS NAME
END
No I don't believe this is possible.
You could use a stored procedure instead to achieve this functionality.
simply use a udf (User defined Function)
Here you can use IF, ELSE, WHILE etc.
But when you are manipulating data (INSERT, UPDATE, DELETE) then you have to use Stored Procedures because udf's aren't able to do that