I want to know what is the best way to check if a subquery has a set of values. I came up with the following query but I don't think its efficient.
SELECT * FROM SomeTable
WHERE
(
2 IN (SELECT OptionId FROM Table2 WHERE Table2_Id = 1) AND
3 IN (SELECT OptionId FROM Table2 WHERE Table2_Id = 1)
)
I appreciate if anyone can provide me with a better solution.
Thanks
I would use EXISTS subqueries:
SELECT * FROM SomeTable
WHERE EXISTS (SELECT * FROM Table2 WHERE Table2_Id = 1 AND OptionId = 2)
AND EXISTS (SELECT * FROM Table2 WHERE Table2_Id = 1 AND OptionId = 3)
If you have one of the following indexes (Table2_Id,OptionId) or (OptionId,Table2_Id) then you shouldn't have worries about performance.
Edit 1: After reading above comments I think you should JOIN somehow SomeTable with Table2 using a common column thus:
SELECT * FROM SomeTable x
WHERE EXISTS (SELECT * FROM Table2 y WHERE y.Table2_Id = 1 AND y.OptionId = 2 AND x.CommonColumn = y.CommonColumn)
AND EXISTS (SELECT * FROM Table2 y WHERE y.Table2_Id = 1 AND y.OptionId = 3 AND x.CommonColumn = y.CommonColumn)
If this doesn't solve your problem then you should add more infos.
Related
I have a table table1. with columns sn, rt and type
I want to get rows with different rt (i.e rt = 1,2,3) column conditions
(SELECT *
FROM table1
WHERE sn = 'testing' AND rt = 1 AND type = 'pump'
ORDER BY id DESC
LIMIT 1)
UNION
(SELECT *
FROM table1
WHERE sn = 'testing' AND rt = 2 AND type = 'pump'
ORDER BY id DESC
LIMIT 1)
UNION
(SELECT *
FROM table1
WHERE sn = 'testing' AND rt = 3 AND type = 'pump'
ORDER BY id DESC
LIMIT 1)
Currently i am trying the above.
Which is the effective way to get the rows
Use ROW_NUMBER() window function:
SELECT t.*
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY rt ORDER BY id DESC) rn
FROM table1
WHERE sn = 'testing' AND type = 'pump' AND rt IN (1, 2, 3)
) t
WHERE t.rn = 1
You can omit AND rt IN (1, 2, 3) if 1, 2 and 3 are the only possible values for rt.
You'll want to do JOINs between the table and itself, then specify the conditions in the singular WHERE clause. I've done a rough sketch of it below:
SELECT t1.*, t2.*, t3.*
FROM table1 AS t1
JOIN table1 AS t2
ON t1.sn = t2.sn AND t1.type = t2.type -- If you've got more reasonable connections between your datapoints, use them here
JOIN table1 AS t3
ON t.sn = t3.sn AND t1.type = t3.type
WHERE t1.rt = 1 AND t2.rt = 2 AND t3.rt = 3
ORDER BY t1.id DESC
LIMIT 1
Depending on what other requirements you have, you may have to tweak some parts of that. If you want results when t1 has a value but t2 or t3 doesn't you can use a LEFT JOIN instead.
I have a T-SQL query that return X records ordered.
I want to get only on record , for instance, only the 5th record from that result: how ?
Thanks
For that you have to update your query.
I.e in oracle we have rownum that assign rownumber to every row.
You can do like this,
Select * from(
Select a.*, rownum as n from your table) where n = 3;
Something like this.
Try this:
WITH NumberedTable AS
(
SELECT
RowNo = ROW_NUMBER() OVER(ORDER BY <'Order Column here'>)
, *
FROM <'Table Name here'>
)
SELECT *
FROM NumberedTable
WHERE RowNo = <'Record No. here'>
Lets assume we have the following table1:
1 2 3
a x m
a y m
b z m
I want to do an inner join on the table
INNER JOIN tabel2 ON table1.2 = table2.2
Somehow like this, but additional a condition that the value of table1.1 not unique. Thus on table1.1 = b no inner join will occure in this example.
What is the best way to achieve this?
Using a an aggregate in a sub query is how I would do it
SELECT *
FROM table1
JOIN table2
ON table1."2" = table2."2"
JOIN (
SELECT "1"
FROM table1
GROUP BY "1"
HAVING COUNT(*) > 1
) AS sub_q
ON sub_q."1" = table1."1";
Another option might be a cte or temporary table to hold the rows you're joining on
WITH _cte AS
(
SELECT "1"
FROM table1
GROUP BY "1"
HAVING COUNT(*) > 1
)
SELECT *
FROM table1
JOIN table2
ON table1."2" = table2."2"
JOIN _cte AS cte
ON cte."1" = table1."1";
temp table:
CREATE TEMPORARY TABLE _tab
(
"1" varchar
);
INSERT INTO _tab
SELECT "1"
FROM table1
GROUP BY "1"
HAVING COUNT(*) > 1;
SELECT *
FROM table1
JOIN table2
ON table1."2" = table2."2"
JOIN _tab AS tab
ON tab."1" = table1."1";
I just want to know if this is possible
To select or update data, but only if another query returns zero results
so something like this
Update A from tableA A
Set A.value = 'test'
where count(select * from tableB Where B.date = A.date) = 0
Yes, you should be able to write an UPDATE query with this logic. You may use an EXISTS clause here:
UPDATE tableA a
SET value = 'test'
WHERE NOT EXISTS (SELECT 1 FROM tableB b WHERE a.date = b.date);
Probably this:
Update tableA
Set tableA.value = 'test'
where (select count(*) from tableB B Where B.date = tableA.date) = 0
Below sample query is a part of my main query. I found SORT operator in below query is consuming 30% of the cost.
To avoid SORT, there is need of creation of Indexes. Is there any other way to optimize this code.
SELECT TOP 1 CONVERT( DATE, T_Date) AS T_Date
FROM TableA
WHERE ID = r.ID
AND Status = 3
AND TableA_ID >ISNULL((
SELECT TOP 1 TableA_ID
FROM TableA
WHERE ID = r.ID
AND Status <> 3
ORDER BY T_Date DESC
), 0)
ORDER BY T_Date ASC
Looks like you can use not exists rather than the sorts. I think you'll probably get a better performance boost by use a CTE or derived table instead of the a scalar subquery.
select *
from r ... left outer join
(
select ID, min(t_date) as min_date from TableA t1
where status = 3 and not exists (
select 1 from TableA t2
where t2.ID = t1.ID
and t2.status <> 3 and t2.t_date > t1.t_date
)
group by ID
) as md on md.ID = r.ID ...
or
select *
from r ... left outer join
(
select t1.ID, min(t1.t_date) as min_date
from TableA t1 left outer join TableA t2
on t2.ID = t1.ID and t2.status <> 3
where t1.status = 3 and t1.t_date < t2.t_date
group by t1.ID
having count(t2.ID) = 0
) as md on md.ID = r.ID ...
It also appears that you're relying on an identity column but it's not clear what those values mean. I'm basically ignoring it and using the date column instead.
Try this:
SELECT TOP 1 CONVERT( DATE, T_Date) AS T_Date
FROM TableA a1
LEFT JOIN (
SELECT ID, MAX(TableA_ID) AS MaxAID
FROM TableA
WHERE Status <> 3
GROUP BY ID
) a2 ON a2.ID = a1.ID AND a1.TableA_ID > coalesce(a2.MAXAID,0)
WHERE a1.ID = r.ID AND a1.Status = 3
ORDER BY T_Date ASC
The use of TOP 1 in combination with the unexplained r alias concern me. There's almost certainly a MUCH better way to get this data into your results that doesn't involve doing this in a sub query (unless this is for an APPLY operation).