In some SQL dialects, you can state (something as):
SELECT * FROM SomeTable WHERE (val1,val2) IN
(SELECT val1,val2 FROM SomeOtherTable)
But I don't know how to do that in the TSQL (sql server 2k) I am using.
I am aware of (and using for now) workarounds like using joins or concatenated values,
but is there some syntax in TSQL I am overlooking to do just that?
UPDATE : This is valid SQL-99 syntax, that's why I consider a join a workaround, even if it would be more performant. My question is maybe put better as :
Is there an implementation of this syntax in TSQL?
UPDATE2 : I just tested this syntax om Mysql and it works fine there.
SELECT *
FROM SomeTable st
WHERE EXISTS
(
SELECT 1
FROM SomeOtherTable sot
WHERE sot.val1 = st.val1
AND sot.val2 = st.val2
)
This is actually what an IN construct is optimized to with any SEMI JOIN method.
As for your question,
Is there an implementation of this syntax in T-SQL?
the answer is no
As documentation says:
… subquery that has a result set of one column. This column must have the same data type as test_expression.
There is not a sql server implementation of that syntax. You'll have to do something like this:
SELECT st.*
FROM SomeTable st
INNER JOIN
(
SELECT val1, val2
FROM SomeOtherTable
GROUP BY val1, val2
) sot ON sot.val1= st.val1 AND sot.val2 = st.val2
Joining would be the way to go here.
IN only works on single column arrays. Since you've explicitly stated that you want to do an IN clause:
SELECT * FROM SomeTable
WHERE val1 IN (SELECT val1 FROM SomeOtherTable WHERE val2 = SomeTable.val2)
AND val2 IN (SELECT val2 FROM SomeOtherTable WHERE val1 = SomeTable.val1)
Check out the documentation on it. Since there's a where clause which depended on each row (e.g.-WHERE SomeOtherTable.ID = SomeTable.MyOtherID), it will hose performance, and a join is absolutely the way to go.
Select SomeTable.*
FROM SomeTable, SomeOtherTable
WHERE SomeTable.Val1 = SomeOtherTable.Val1
And SomeTable.Val2 = SoemeOtherTable.Val2
You should not consider this a "workaround." This is the most basic and standard way of accomplishing what you want to accomplish.
Edit: It may not be your standard "JOIN" syntax, but it's a habit.
Related
Can you set multiple column names from a SQL table as a macro in SQL to query against?
For example I have multiple columns I am hitting against multiple times, can I use a macro or some type of reference to identify them ONCE to avoid displaying them repetitively and cluttering up the code?
The current code works, I am just looking for a cleaner/streamlined option.
Current Code:
WHERE ('ABC') IN
([CODE1],[CODE2],[CODE3],[CODE4],[CODE5],[CODE6],[CODE7],[CODE8]
,[CODE9],[CODE10],[CODE11],[CODE12],[CODE13],[CODE14],[CODE15]
,[CODE16],[CODE17],[CODE18],[CODE19],[CODE20],[CODE21],[CODE22]
,[CODE23],[CODE24],[CODE25]
AND ('CFS') IN
([CODE1],[CODE2],[CODE3],[CODE4],[CODE5],[CODE6],[CODE7],[CODE8]
,[CODE9],[CODE10],[CODE11],[CODE12],[CODE13],[CODE14],[CODE15]
,[CODE16],[CODE17],[CODE18],[CODE19],[CODE20],[CODE21],[CODE22]
,[CODE23],[CODE24],[CODE25]
ect...(20 more times)
Goal:
WHERE 'ABC' IN (&columnsmentionedabove)
OR 'FGS' in (&columnsmentionedabove)
OR 'g6s' in (&columnsmentionedabove)
etc.....
This is inherited code and just seems very clunky.
Thank you
Numbered columns like this are almost always a sign you should have an additional table. So if your existing table structure is like this:
Table1
Table1ID, OtherFields, Code1, Code2, Code3.... Code25
You really want something more like this:
Table1
Table1ID, OtherFields
Table1Codes
Table1ID, Code
Where each entry in Table1 will have many entries in Table1Codes. Then you write JOIN statements to show the two sets side-by-side when needed.
FROM Table1 t
INNER JOIN Table1Codes tc1 ON tc.Table1ID = t.Table1ID AND tc.Code = 'ABC'
INNER JOIN Table1Codes tc2 ON tc.Table1ID = t.Table1ID AND tc.Code = 'CFS'
Or
FROM Table1 t
INNER JOIN Table1Codes tc1 ON tc.Table1ID = t.Table1ID AND tc.Code IN ('ABC','FGS','g6s')
If you can't change the table's schema, as in often the case, you can UNPIVOT it. For example, assuming CODE1...CODE25 come from MyTable, wrap the UNPIVOT operation inside a CTE:
;WITH
cte AS
(
SELECT upvt.*
FROM MyTable
UNPIVOT (
CodeValue FOR CodeLabel IN ([CODE1], [CODE2], ..., [CODE25])
) upvt
)
SELECT *
FROM cte
WHERE CodeValue IN ('ABC', 'DEF', ...)
The unpivot operation is not free. Make sure you filter as much as possible from MyTable before unpivoting the it.
I want to know if there are any restrictions on using FireDAC's "LIMIT" macrofunction on subqueries like this:
SELECT TOP 10 * FROM TABLE1 WHERE NOT EXISTS( SELECT TOP 1 FIELD1 FROM TABLE2 )
With LIMIT applied it would be as follows:
SELECT {LIMIT(0,10)} * FROM TABLE WHERE NOT EXISTS( SELECT {LIMIT(0,10)} FIELD1 FROM TABLE2 )
If so, I would like to know what alternatives exist to limit the number of rows returned in a subquery considering that it is necessary to be compatible with more than one database manager (Oracle and SQL Server).
This is a simplified use case, in a real scenario it is expected to use this macrofunction in much more complex queries.
Thanks in advance.
I think my head is muddy or something. I'm trying to figure out how a t-sql update works without a join when updating one table from another. I've always used joins in the past but came across a stored proc where someone else created one without a join. This update is being used in SQL 2008R2 and it works.
Update table1
SET col1 = (SELECT TOP 1 colX FROM table2 WHERE colZ = colY),
col2 = (SELECT TOP 1 colE FROM table2 WHERE colZ = colY)
Obviously, colY is a field in table1. To get the same results in a select statement (not update), a join is required. I guess I don't understand how an update works behind the scenes but it must be doing some kind of join?
SQL Server translates those subqueries into joins. You can look at this by getting the query plan. You can write an equivalent query with UPDATE ... FROM ... JOIN syntax and observe the query plan to be essentially the same.
The sample code shown is unusual, hard to understand, redundant and inflexible. I recommend against using this style.
No it's doing a sub query, well two in this case. Be damn painful if you have another 98 col fields.
You can do something similar for select
select *,
(SELECT TOP 1 colX FROM table2 WHERE colZ = colY) as col1
From table1
A left join would simply be more efficient
Your example unless the dbms optimises it it running the subquery(ies) for each row in table.
Got to say whoever wrote it is less than competent.
These subqueries are what is called correlated subqueries. If you were to write the same query as a SELECT rather than an UPDATE it would look like this.
SELECT col1 = (SELECT TOP 1 table2.colX FROM table2 WHERE table2.colZ = table1.colY),
col2 = (SELECT TOP 1 table2.colE FROM table2 WHERE table2.colZ = table1.colY)
FROM table1
The JOIN is in the fact that you are referencing a column from an outside table on the inside of the subquery. Table1 is referenced in the UPDATE command. You can include a FROM clause but it isn't required for a setup like this.
You can use the same syntax in a SELECT with no join, but you need to alias the table if colY also exists in table2
SELECT (SELECT TOP 1 colX FROM table2 WHERE colZ = T.colY)
, (SELECT TOP 1 colE FROM table2 WHERE colZ = T.colY)
FROM table1 AS T
I only ever use this sort of thing when building up an ad hoc query just for my own infomation. If it's going to be put into any sort of permanent code I'll convert it to a join as it's easier to read and more maintainable.
i am converting multiple rows in to a array using array_agg() function,
and i need to give that array to a select statements where condition.
My query is,
SELECT * FROM table WHERE id =
ALL(SELECT array_agg(id) FROM table WHERE some_condition)
but it gives error, how can i over come it..
the error has been cleared by type casting the array, using my query like this
SELECT * FROM table WHERE id =
ALL((SELECT array_agg(id) FROM table WHERE some_condition)::bigint[])
reference link
It seems like you are over-complicating things. As far as I can tell, your query should be equivalent to simple:
SELECT * FROM table WHERE some_condition
Or, if you are selecting from 2 different tables, use join:
SELECT table1.*
FROM table1
JOIN table2 ON table1.id = table2.id
WHERE some_condition
Not only this is simpler, it is also faster than fiddling with arrays.
I have written query, I wanted to know the effect of usage of IN clause in Query.
Query I
Select * from khatapayment_track
Where Property_ID IN (Select Property_id from khata_header where DIV_ID=2)
Query II
Select * from khatapayment_track KPT, khata_header KH
Where kh.Property_id=KPT.Property_id and KH.DIV_Id=2
I would like to know
1) which one is faster
2) Any effects of using IN clause, is it advisable to use if a query has a 3 IN clause.
Can you please help me with examples
Your second query is faster, but it is better to use joins (it looks nicer and it have the same execution plan):
select
*
from
khatapayment_track t
inner join khata_header h on (h.property_id = t.property_id)
where
h.div_id = 2
Also you can use mysql profiler to compare your queries.
Query II is faster in your example as you are using subquery in Query I.
but consider follwing example which returns similar o/p but query i will returns faster
select * from tableName where id in (1,2,3,4)
is similar to
select * from tableName where id =1 OR id =2 OR id =3 Or id =4