Convert Sql Server Query from In -> Exists? - sql-server

I want to convert this query :
SELECT *
FROM myTable
WHERE dateCreated = (
SELECT MAX(dateCreated)
FROM myTable
)
AND duty IS NULL
AND CompanyPayingId IN
(43081 ,43082 ,43084 ,43085)
to change from in to Exists query ( due to performance) :
However I'm having trouble converting the code cause I think I'll have to duplicate the where clause...
How can I convert this code ?

I can do like this:
create table num(idn int)
insert into num values(43081) ,(43082),(43084) ,(43085)
select * from num
SELECT *
FROM myTable m inner join num n
ON m.dateCreated = (SELECT MAX(dateCreated) FROM myTable)
AND m.duty IS NULL
AND m.CompanyPayingId=n.num

Related

Create a SELECT with defined number of rows

I have a stored procedure that should insert some random rows in a table depending on the amount values
#amount1 INT --EligibilityID = 1
#amount2 INT --EligibilityID = 2
#amount3 INT --EligibilityID = 3
Maybe the obvious way is to use TOP(#amount) but there are a lot of amount values and the second select is much larger. So, I was looking for a way to do it in a single statement if possible.
INSERT INTO [dbo].[CaseInfo]
SELECT ([EligibilityID],[CaseNumber],[CaseMonth])
FROM (
SELECT TOP(#amount1) [EligibilityID],[CaseNumber],[CaseMonth]
FROM [dbo].[tempCases]
WHERE [EligibilityID] = 1
)
INSERT INTO [dbo].[CaseInfo]
SELECT ([EligibilityID],[CaseNumber],[CaseMonth])
FROM (
SELECT TOP(#amount2) [EligibilityID],[CaseNumber],[CaseMonth]
FROM [dbo].[tempCases]
WHERE [EligibilityID] = 2
)
INSERT INTO [dbo].[CaseInfo]
SELECT ([EligibilityID],[CaseNumber],[CaseMonth])
FROM (
SELECT TOP(#amount3) [EligibilityID],[CaseNumber],[CaseMonth]
FROM [dbo].[tempCases]
WHERE [EligibilityID] = 3
)
I would recommend to use row_number, partitioned by eligibilityID, and then compare it with a case statement to select the correct variable each time:
INSERT INTO [dbo].[CaseInfo]
SELECT ([EligibilityID],[CaseNumber],[CaseMonth])
FROM (
SELECT [EligibilityID],[CaseNumber],[CaseMonth]
,row_number() over (partition by EligibilityID order by CaseNumber) as rn -- you haven't mentioned an ORDER BY, you can change it here
FROM [dbo].[tempCases]
) as table1
where rn<=case
when EligibilityID=1 then #amount1
when EligibilityID=2 then #amount2
when EligibilityID=3 then #amount3
end

Subquery reference newly created column

I have been trying to write a subquery based on the SQL Server docs. I am trying to write a SQL Server query to
cast a varchar to an int
select rows where the varchar is null.
My logic is:
outer select+ where clause gets all rows where the new column (q5int) is NULL
create inner select that performs the cast and creates the new column (q5int)
What am I doing wrong? I would appreciate an explanation of whats wrong with my logic, not just how to fix my code.
select *
from
(select
*, cast (NULLIF(q5,'NULL') as int) as q5int
from
ft_merge)
where
q5int = NULL
You can do this sans the sub-query
select *
from ft_merge
WHERE try_convert(int,q5) is null
Let us analyze your query first
select * from (
select *,cast (NULLIF(q5,'NULL') as int) as q5int
from ft_merge
) WHERE q5int=NULL
1.NULLIF(q5,'NULL') should be NULLIF(q5,NULL) not in quotes
2.WHERE q5int=NULL should be replaced with "q5int IS NULL"
Creating test data
Select * into #ft_merge
from
(
Select 1 AS ID,'111' AS q5
union
Select 2, null
union
Select 3,'2222'
union
Select 4,null
)t
/* using your query */
select * from (
select *,cast(q5 as int) as q5int
from #ft_merge where ISNUMERIC(q5) > 0 or q5 is null
)t WHERE q5int is NULL
/* another optimal way of doing this */
select *,cast(q5 as int) as q5int
from #ft_merge where NULLIF(q5,NULL) is null

Update row based on previous row id

I have an update query like so
UPDATE myTable
SET ParentID = X
I need X to be the ID of the previous row that is currently being updated.
Any ideas?
If by "previous" row you mean the row where the id is the biggest value less than the value in the current row, you can use the lag() function in SQL Server 2012 or a correlated subquery:
UPDATE myTable
SET ParentID = (select top 1 id
from mytable m2
where m2.id < myTable.id
order by id desc
)
Maybe the following script will be useful (Assuming that the first value not have previous value then will be NULL), you can try this HERE:
CREATE TABLE TEST(
ID INT);
INSERT INTO TEST VALUES(10);
INSERT INTO TEST VALUES(20);
INSERT INTO TEST VALUES(30);
INSERT INTO TEST VALUES(40);
INSERT INTO TEST VALUES(50);
INSERT INTO TEST VALUES(60);
/*HERE THE SCRIPT*/
WITH temp AS (
SELECT x.ID,
ROW_NUMBER() over (order by x.ID) AS n
FROM TEST x
)
UPDATE t
SET t.ID = (SELECT temp.ID FROM temp WHERE temp.n = t.n - 1)
FROM (
SELECT x.ID,
ROW_NUMBER() over (order by x.ID) AS n
FROM TEST x
) t
SELECT * FROM TEST
NOTE: maybe this can be solved in an easier way, but it was the first thing that occurred to me with what you have posted

T-SQL: accessing temporary column in Common Table Expression

Is it possible to access a temporary column that was defined in a query for a Common Table Expression? Say I have
select * from myTable
;with cte as
(
select
*, Salary * 4 as FourTimesSalary
from
Employees
where
Name = #name
and ID >= 100
)
Is there a way to use the temporary column FourTimesSalary when querying cte like so?
select top 2 *
from cte
order by FourTimesSalary, Name
TIA.
Yes you can do that. Example:
with temp as
(
select 1 as id, 2*4 as val
UNION
select 2 as id, 3*4 as val
)
SELECT * FROM temp ORDER BY VAL desc
Your example looks fine, did you get an error when you tried that or something?

How to avoid NULL when using Value-Name Mapping in SQL

I have a table like the following which is basically used to "give a name" to a value in a table (this table contains values for a bunch of other tables as well, not just for MYTABLE; I've omitted a few irrelevant fields from NAMEVALUEMAP):
NAMEVALUEMAP Table
---------------------
VALUE_ | NAME_
---------------------
0 | ZERO
1 | ONE
I didn't want to use JOINs so I thought of using Sub-Queries.
Problem is when a value does not exist in the NAMEVALUEMAP table then NULL is shown.
Instead of NULL I want to show the actual value from MYTABLE (MYTABLE has ID field as identity column and contains a few rows):
-- //Fine, prints word 'ZERO' when MYTABLE.ABC is 0
SELECT
(SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = (SELECT ABC FROM MYTABLE inner_ WHERE inner_.ID = outer_.ID))
FROM
MYTABLE outer_
-- //Not Fine, prints NULL (because "999" is not in NAMEVALUEMAP). In this case, MYTABLE.ABC is 999
-- //Want it to print 999 if the value is not in NAMEVALUEMAP
SELECT
(SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = (SELECT ABC FROM MYTABLE inner_ WHERE inner_.ID = outer_.ID))
FROM
MYTABLE outer_
-- //Tried COALESCE, but the error is "Invalid column name 'VALUE_'"
SELECT
COALESCE((SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = (SELECT ABC FROM MYTABLE inner_ WHERE inner_.ID = outer_.ID)), ABC)
FROM
MYTABLE outer_
Also, is there a better way to do this sort of value-to-name mapping?
I would recomend using a LEFT JOIN (is there any reason you are voidung it?) and ISNULL
SELECT ISNULL(NAME_, ABC)
FROM MYTABLE m LEFT JOIN
NAMEVALUEMAP n ON m.ABC = n.VALUE_
Well, in that case you can try
SELECT ISNULL((select NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = m.ABC), m.ABC)
FROM MYTABLE m
It is a left join, unless you want soem EXISTS/UNION construct. Not tested:
SELECT
COALESCE(N.VALUE, M.ABC)
FROM
MYTABLE M
LEFT JOIN
NAMEVALUEMAP N ON M.VALUE N.ABC
If you really want to avoid JOINs...
SELECT
ABC
FROM
MYTABLE M
WHERE
NOT EXISTS (SELECT * FROM NAMEVALUEMAP N WHERE M.VALUE N.ABC)
UNION ALL
SELECT
VALUE
FROM
NAMEVALUEMAP N
WHERE
EXISTS (SELECT * FROM MYTABLE M WHERE M.VALUE N.ABC)
Edit:
The SELECT *, 1 or NULL in EXISTS question again
Try EXISTS (SELECT 1/0...)
Mentioned in ANSI SQL 1992 Standard too, page 191
EDIT:
SELECT
COALESCE(
(SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ =
(SELECT ABC FROM MYINNERTABLE inner_ WHERE inner_.ID = outer_.ID)
),
<int to string>(
SELECT ABC FROM MYINNERTABLE inner_ WHERE inner_.ID = outer_.ID
)
)
FROM
MYTABLE outer_
where column function <int to string> is appropriate for sqlserver. In mysql it would be CAST(). Without conversion, the query will throw a wobbly about the mismatched datatypes.

Resources