I want to create a statement like the following:
if (select statement1 returns rows){
select statement2
}
else {
select statement3
}
This if statement is part of a bigger query
select from products where p.id in (
if (select statement1 returns rows){
select statement2
}
else {
select statement3
}
Is this possible in SQL Server, or is my thinking incorrect?
You need to use a combination of EXISTS and CASE..END:
select *
from products
where p.id in (
case when (exists ( <statement1> ))
then ( <statement2> )
else ( <statement3> )
end
)
Where <statement1> might be: SELECT * FROM Customer WHERE Id = 123
<statement2> might be: SELECT MIN(field) FROM someTable
<statement3> might be: SELECT 0 as DefaultValue
If you can show some examples of what you want those actual statements to be I can provide a more concrete answer.
Actually SQL is more rigid, due to performance considerations. Your query will look more like this:
select *
from products
where 1 = case when (exists ( <statement1> ))
then case when p.id in ( <statement2> ) then 1 else 0 end
else case when p.id in ( <statement3> ) then 1 else 0 end
end
Since you are checking for the same id existance, I think you could do a UNION here.
select *
from products
where p.id in (select id from table1
union
select id from table2)
I'd recommend using a UNION between your two conditions to help avoid performance problems...and may be easier to read as well.
SELECT FROM products p
WHERE EXISTS (SELECT STATEMENT1)
AND EXISTS (SELECT STATEMENT2 s2 WHERE s2.p_id = p.id)
UNION
SELECT FROM products p
WHERE NOT EXISTS (SELECT STATEMENT1)
AND EXISTS (SELECT STATEMENT3 s3 WHERE s3.p_id = p.id)
Depending on the nature of the statements, you might be able to leave off the Not Exists in the second select.
Related
Using C# and Linq to SQL, I found that my query with multiple where is orders of magnitude slower than with a single where / and.
Here is the query
using (TeradiodeDataContext dc = new TeradiodeDataContext())
{
var filterPartNumberID = 71;
var diodeIDsInBlades = (from bd in dc.BladeDiodes
select bd.DiodeID.Value).Distinct();
var diodesWithTestData = (from t in dc.Tests
join tt in dc.TestTypes on t.TestTypeID equals tt.ID
where tt.DevicePartNumberID == filterPartNumberID
select t.DeviceID.Value).Distinct();
var result = (from d in dc.Diodes
where d.DevicePartNumberID == filterPartNumberID
where diodesWithTestData.Contains(d.ID)
where !diodeIDsInBlades.Contains(d.ID)
orderby d.Name
select d);
var list = result.ToList();
// ~15 seconds
}
However, when the condition in the final query is this
where d.DevicePartNumberID == filterPartNumberID
& diodesWithTestData.Contains(d.ID)
& !diodeIDsInBlades.Contains(d.ID)
// milliseconds
it is very fast.
Comparing the SQL in result before calling ToList(), here are the queries (value 71 manually added in place of #params)
-- MULTIPLE WHERE
SELECT [t0].[ID], [t0].[Name], [t0].[M2MID], [t0].[DevicePartNumberID], [t0].[Comments], [t0].[Hold]
FROM [dbo].[Diode] AS [t0]
WHERE (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t2].[value]
FROM (
SELECT [t1].[DiodeID] AS [value]
FROM [dbo].[BladeDiode] AS [t1]
) AS [t2]
) AS [t3]
WHERE [t3].[value] = [t0].[ID]
))) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t6].[value]
FROM (
SELECT [t4].[DeviceID] AS [value], [t5].[DevicePartNumberID]
FROM [dbo].[Test] AS [t4]
INNER JOIN [dbo].[TestType] AS [t5] ON [t4].[TestTypeID] = ([t5].[ID])
) AS [t6]
WHERE [t6].[DevicePartNumberID] = (71)
) AS [t7]
WHERE [t7].[value] = [t0].[ID]
)) AND ([t0].[DevicePartNumberID] = 71)
ORDER BY [t0].[Name]
and
-- SINGLE WHERE
SELECT [t0].[ID], [t0].[Name], [t0].[M2MID], [t0].[DevicePartNumberID], [t0].[Comments], [t0].[Hold]
FROM [dbo].[Diode] AS [t0]
WHERE ([t0].[DevicePartNumberID] = 71) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t3].[value]
FROM (
SELECT [t1].[DeviceID] AS [value], [t2].[DevicePartNumberID]
FROM [dbo].[Test] AS [t1]
INNER JOIN [dbo].[TestType] AS [t2] ON [t1].[TestTypeID] = ([t2].[ID])
) AS [t3]
WHERE [t3].[DevicePartNumberID] = (71)
) AS [t4]
WHERE [t4].[value] = [t0].[ID]
)) AND (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t6].[value]
FROM (
SELECT [t5].[DiodeID] AS [value]
FROM [dbo].[BladeDiode] AS [t5]
) AS [t6]
) AS [t7]
WHERE [t7].[value] = [t0].[ID]
)))
ORDER BY [t0].[Name]
The two SQL queries execute in < 1 second in SSMS and produce the same results.
So I'm wondering why the first is slower on the LINQ side. It's worrying to me because I know I've used multiple where elsewhere, without being aware of a such a severe performance impact.
This question even has answered with both multiple & and where. And this answer even suggests using multiple where clauses.
Can anyone explain why this happens in my case?
Because writing like this
if (someParam1 != 0)
{
myQuery = myQuery.Where(q => q.SomeField1 == someParam1)
}
if (someParam2 != 0)
{
myQuery = myQuery.Where(q => q.SomeField2 == someParam2)
}
is NOT(upd) the same as (in case when someParam1 and someParam2 != 0)
myQuery = from t in Table
where t.SomeField1 == someParam1
&& t.SomeField2 == someParam2
select t;
is (NOT deleted) the same as
myQuery = from t in Table
where t.SomeField1 == someParam1
where t.SomeField2 == someParam2
select t;
UPD
Yes, I do mistake. Second query is same, first is not same.
First and Second queries not EXACTLY the same. Let me show you what I mean.
1st query with lamda-expression writen as
t.Where(r => t.SomeField1 == someParam1 && t.SomeField2 == someParam2)
2nd query as
t.Where(r => r.SomeField1 == someParam1).Where(r => r.SomeField2 == someParam2)
In this case in generated SQL Predicate with SomeField2 goes first (it is important, see below)
In 1st case we getting this SQL:
SELECT <all field from Table>
FROM table t
WHERE t.SomeField1 = :someParam1
AND t.SomeField2 = :someParam2
In 2 case the SQL is:
SELECT <all field from Table>
FROM table t
WHERE t.SomeField2 = :someParam2
AND t.SomeField1 = :someParam1
As we see there are 2 'same' SQLs. As we see, the OP's SQLs are also 'same', they are different in order of predicates in WHERE clause (as in my example). And I guess that SQL optimizer generate 2 different execution plans and may be(!!!) doing NOT EXISTS, then EXISTS and then filtering take more time than do first filtering and after that do EXISTS and NOT EXISTS
UPD2
It is a 'problem' of Linq Provider (ORM). I'm using another ORM (linq2db), and it generates for me EXACTLY the same SQLs in both cases.
I have a problem, in example: I have a range of ids of integers (from 1 to 1000), this range supposed to be ids in a SQL Server table, and I want to detect which numbers of this range are not in the table, and sorry for my bad english, thank you
another simpler option would be to use the following query
SELECT number
FROM master..spt_values
WHERE number BETWEEN 1 AND 1000
AND NOT EXISTS ( SELECT 1
FROM Your_Table t --<-- your table where you are checking
WHERE t.ID = number) -- the missing values
GROUP BY number
The above solution is only good if you are looking for around 1000 values. For more values you would need to modify it little bit, something like
-- Select the maximum number or IDs you want to check
DECLARE #Max_Num INT = 10000;
;WITH CTE AS
(
SELECT TOP (#Max_Num) ROW_NUMBER() OVER ( ORDER BY (SELECT NULL)) numbers
FROM master..spt_values v1 cross join master..spt_values v2
)
SELECT c.numbers
FROM CTE c
WHERE NOT EXISTS (SELECT 1
FROM Your_table t
WHERE t.ID = c.numbers)
One way to find "holes" is to generate a list of all possible values and then look for the ones that aren't there. If you can survive with a list of a missing value and then the number of subsequent values following it, you can do this with another method.
SQL Server 2012+ supports lead() and lag(). The following gets almost everything, except for initial missing values:
select t.id + 1 as missingid,
(coalesce(t.nextid, 1000) - t.id - 1) as nummissing
from (select t.*, lead(t.id) over (order by t.id) as nextid
from table t
t.id between 1 and 1000
) t
where t.nextid > t.id + 1 or
(t.nextid is null and t.id <> 1000)
You can get these with a little piece of special logic:
select (case when t.previd is null then 1
else t.id + 1
end) as missingid,
(case when t.previd is null then t.id - 1
else (coalesce(t.nextid, 1000) - t.id - 1)
end) as nummissing
from (select t.*, lead(t.id) over (order by t.id) as nextid,
lag(t.id) over (order by t.id) as previd
from table t
where t.id between 1 and 1000 and
) t
where (t.nextid > t.id + 1 or
(t.nextid is null and t.id <> 1000)
(t.previd is null and t.id <> 1)
)
This sounds like one of the many scenarios where it is helpful to have a numbers table:
SELECT *
FROM lkp_Numbers a
WHERE NOT EXISTS (SELECT 1
FROM YourTable b
WHERE a.num = b.Id)
AND num <= 1000
I use this to create a numbers table:
DROP TABLE lkp_Numbers
DECLARE #RunDate datetime
SET #RunDate=GETDATE()
SELECT TOP 1000 IDENTITY(int,1,1) AS Num
INTO lkp_Numbers
FROM sys.objects s1, sys.objects s2, sys.objects s3
ALTER TABLE lkp_Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Num)
That method for creating a numbers table was found here: What is the best way to create and populate a numbers table?
I am generating a report in php (mysql),
ex:
`select count(id) as tot_user from user_table
select count(id) as tot_cat from cat_table
select count(id) as tot_course from course_table`
Like this I have 12 tables.
Can i make it in single query. If i did? Process gets slow?
SELECT (
SELECT COUNT(*)
FROM user_table
) AS tot_user,
(
SELECT COUNT(*)
FROM cat_table
) AS tot_cat,
(
SELECT COUNT(*)
FROM course_table
) AS tot_course
If you use MyISAM tables, the fastest way is querying directly the stats:
select table_name, table_rows
from information_schema.tables
where
table_schema='databasename' and
table_name in ('user_table','cat_table','course_table')
If you have InnoDB you have to query with count() as the reported value in information_schema.tables is wrong.
You can certainly us the a Select Agregation statement as Postulated by Ben James, However This will result in a view with as many columns as you have tables. An alternate method may be as follows:
SELECT COUNT(user_table.id) AS TableCount,'user_table' AS TableSource FROM user_table
UNION SELECT COUNT(cat_table.id) AS TableCount,'cat_table' AS TableSource FROM cat_table
UNION SELECT COUNT(course_table.id) AS TableCount, 'course_table' AS TableSource From course_table;
The Nice thing about an approch like this is that you can explicitly write the Union statements and generate a view or create a temp table to hold values that are added consecutively from a Proc cals using variables in place of your table names. I tend to go more with the latter, but it really depends on personal preference and application. If you are sure the tables will never change, you want the data in a single row format, and you will not be adding tables. stick with Ben James' solution. Otherwise I'd advise flexibility, you can always hack a cross tab struc.
select RTRIM(A.FIELD) from SCHEMA.TABLE A where RTRIM(A.FIELD) = ('10544175A')
UNION
select RTRIM(A.FIELD) from SCHEMA.TABLE A where RTRIM(A.FIELD) = ('10328189B')
UNION
select RTRIM(A.FIELD) from SCHEMA.TABLE A where RTRIM(A.FIELD) = ('103498732H')
SELECT t1.credit,
t2.debit
FROM (SELECT Sum(c.total_amount) AS credit
FROM credit c
WHERE c.status = "a") AS t1,
(SELECT Sum(d.total_amount) AS debit
FROM debit d
WHERE d.status = "a") AS t2
I know this is an old stack but i will post this Multi-SQL select case
SELECT bp.bizid, bp.usrid, bp.website,
ROUND((SELECT SUM(rating) FROM ratings WHERE bizid=bp.bizid)/(SELECT COUNT(*) FROM ratings WHERE bizid=bp.bizid), 1) AS 'ratings',
(SELECT COUNT(*) FROM bzreviews WHERE bizid=bp.bizid) AS 'ttlreviews',
bp.phoneno, als.bizname,
(SELECT COUNT(*) FROM endorsment WHERE bizid=bp.bizid) AS 'endorses'
, als.imgname, bp.`location`, bp.`ownership`,
(SELECT COUNT(*) FROM follows WHERE bizid=bp.bizid) AS 'followers',
bp.categories, bp.openhours, bp.bizdecri FROM bizprofile AS bp
INNER JOIN alluser AS als ON bp.usrid=als.userid
WHERE als.usertype='Business'
if not exists(SELECT 1 FROM MYTABLE1 WHERE ID=#ID)
BEGIN
END
I want to check for this ID value in MYTABLE2 as well..how should I write the IF condition ?? i want to check that a certain ID doesnt exist in any of the two tables.
You could use an UNION ALL:
IF NOT EXISTS (SELECT 1 FROM
(SELECT ID FROM MyTable1
UNION ALL
SELECT ID FROM MyTable2) Table
WHERE ID = #ID)
BEGIN
...
END
You could do the following:
if (not exists(SELECT 1 FROM MYTABLE1 WHERE ID=#ID))
AND (not exists(SELECT 1 FROM MYTABLE2 WHERE ID=#ID))
BEGIN
END
Depends on what you want -
If you want to check that the ID exists in either ONE of the tables then use UNION ALL. you could use JNK's answer.
If you want to check that the ID exists in both tables then use INNER JOIN.
If not exists
(select top 1 from table1 a inner join
Table2 b on a.ID = b.ID where a.ID = #ID)
BEGIN
END
Hope this helps.
SELECT
blah.ID
FROM
MYTABLE1 as blah
WHERE
blah.ID IN (some range of ints)
If you get no results then you know it does not exist
I have a problem that I know how to solve in SQL but not with Linq to Entities.
My data looks like this:
ID GROUP TIMESTAMP
-- ----- ---------
1 A 2011-06-20
2 A 2011-06-21
3 B 2011-06-21
4 B 2011-06-22
5 B 2011-06-23
6 C 2011-06-30
I want to retrieve all the Entity objects (not just the ID) such that I am only getting the most recent record from each group. (ie. the records with ids 2, 5, 6)
In SQL I would do something like this:
SELECT * FROM my_table a
WHERE a.timestamp =
(SELECT MAX(timestamp) FROM my_table b
WHERE a.group = b.group)
(For the sake of this question you can assume that timestamp is unique within each group).
I'd like to do this query against a WCF Data Service using Linq to Entities but I can't seem to have a nested query that references the outside query like this. Can anyone help?
Possibly not as clean and efficient as the hand written version but here's what I came up with
var q = from a in db.MyEntities
where a.Timestamp == (from b in db.MyEntities
where b.Group == a.Group
select b.Timestamp).Max()
select a;
which translates into this SQL
SELECT
[Project1].[Id] AS [Id],
[Project1].[Group] AS [Group],
[Project1].[Timestamp] AS [Timestamp]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Group] AS [Group],
[Extent1].[Timestamp] AS [Timestamp],
[SSQTAB1].[A1] AS [C1]
FROM [MyEntities] AS [Extent1]
OUTER APPLY
(SELECT
MAX([Extent2].[Timestamp]) AS [A1]
FROM [MyEntities] AS [Extent2]
WHERE [Extent2].[Group] = [Extent1].[Group]) AS [SSQTAB1]
) AS [Project1]
WHERE [Project1].[Timestamp] = [Project1].[C1]
Hi try to use linqer that will convert your sql statements to linq query.
Linqer
Best Regards
This should work:
var query = db.my_table
.GroupBy(p=>p.group)
.Select(p=>p.OrderByDescending(q=>q.timestamp).First());
Here you go.A simple way to do.
var result = (from x in my_table
group x by x.Group into g
select new
{
g.Key,
timestamp = g.Max(x => x.TimeStamp),
g //This will return everything in g
});