So I am trying to use CROSS APPLY but can't seem to get it rigth.
I have some queries that look like this:
SELECT COL1, COL2
FROM dbo.tableA AS A
WHERE COL3 = (SELECT MAX(COL4)
FROM dbo.tableA AS B
WHERE A.COL1 = B.COL1) AS SUB
The I try this:
SELECT COL1, COL2
FROM dbo.tableA AS A
CROSS APPLY (SELECT MAX(COL4) AS MAX_DATE
FROM TABLEA AS B
WHERE A.COL1 = B.COL1) AS SUB
But I always return more rows when I use the CROSS APPLY. Where is my mistake?
You're missing a WHERE in your second query, if you want the 2 queries to work the same:
SELECT COL1, COL2
FROM dbo.tableA AS A
CROSS APPLY (SELECT MAX(COL4) AS MAX_DATE
FROM TABLEA AS B
WHERE A.COL1 = B.COL1) AS SUB
WHERE A.COL3 = SUB.MAX_DATE;
Apart from the APPLY rewrite, because this is a self-join it can also be done with a MAX window aggregate:
SELECT COL1, COL2
FROM (
SELECT *,
MAX(COL4) OVER (PARTITION BY COL1) AS mx
FROM dbo.tableA
) AS A
WHERE COL3 = mx
Related
I have a Select with sub selects using Top 1 and where clause.
I tried to optimize the select by doing a Left Join of the sub selects but the query time took longer. Is subselect better in this case? I couldnt post my whole select because it is too long and confidential but I will try to recreate the important part below:
Sub Select
SELECT
(select top 1 colId FROM table1 WHERE col1 = b.Id and col2 = 3 Order by 1) Id3,
(select top 1 colId FROM table1 WHERE col1 = b.Id and col2 = 5 Order by 1) Id5,
(select top 1 colId FROM table1 WHERE col1 = b.Id and col2 = 7 Order by 1) Id7
FROM table2 b
Trying it w/ Left Join
SELECT
t1.colid id3,
t2.colid id5,
t3.colid id7
FROM table2 b
LEFT JOIN (
select colId, col1 FROM table1 WHERE col2 = 3
) t1 ON t1.col1 = b.Id
LEFT JOIN (
select colId, col1 FROM table1 WHERE col2 = 5
) t2 ON t1.col1 = b.Id
LEFT JOIN (
select colId, col1 FROM table1 WHERE col2 = 7
) t3 ON t1.col1 = b.Id
Is there a better way to do this? and why is it the Left join takes longer query time?
You can use ROW_NUMBER:
;WITH cte AS
(
SELECT a.colId,
rn = ROWN_NUMBER() OVER (PARTITION BY a.col2 ORDER BY a.col1)
FROM table1 a
LEFT JOIN table2 b on a.col1 = b.id
WHERE a.col2 IN (3,5,7)
)
SELECT *
FROM cte
WHERE rn = 1
This will give you the first row for each col2 value and you can restrict the values you want to 3,5,7.
I have query which will group column 1 and 2 and calculate count for column3
(select col1, col2, count(col3)
from table1
group by col1,col2
Having count(col3) < 50)
But I want to display all fields values for col3 where count(col3) < 50 . Can you help me with this? Thank you
Try this:
select col1, col2, col3, t.cnt
from (
select col1, col2, col3,
count(col3) over (partition by col1, col2) AS cnt
from table1 ) as t
where t.cnt < 50
The idea is to use windowed version of COUNT instead of GROUP BY. COUNT(col3) OVER (PARTITION BY col1, col2) returns the count of col3 occurrences per col1, col2 for every row of table1. You can filter out col1, col2 slices having a count of 50 or more in an outer query.
You can also use something like this:
select t.col1, t.col2, t.col3
from table1 t
where
EXITS(select 1 from table1 t1 where t.col1 = t1.col1 and t.col2 = t.col2 having count(t1.col3) > 50)
or something like this:
select t.col1, t.col2, t.col3
from table1 t
inner join (select t1.col1, t1.col2, count(t1.col3) from table1 t1
group by t1.col1, t1.col2 having count(t1.col3) > 50) x
on t.col1 = x.col1 and t.col2 = x.col2
I am trying to use Row_Number, it works fine in the order by clause, but when using it in the where clause, i get invalid column, that dosnt make sense to me?
Anybody that can explain why that is? Thanks a bunch
SELECT col1,col2,
ROW_NUMBER() OVER(PARTITION BY col2 ORDER BY col2) as rownr
FROM table1 t1 WITH(NOLOCK)
JOIN table2 t2 WITH(NOLOCK) ON t2.id = t1.id
WHERE rownr > 1
ORDER BY rownr,unit
Logical processing of order by is after the select but where clause is processed before select thats why you get that error.
To do that you should make the query as sub-select and filter the records in outer query
SELECT col1,
col2
FROM (SELECT col1,
col2,
Row_number()OVER(PARTITION BY col2 ORDER BY col2) AS rownr,
unit
FROM table1 t1 WITH(NOLOCK)
JOIN table2 t2 WITH(NOLOCK)
ON t2.id = t1.id) a
WHERE rownr > 1
ORDER BY rownr, unit
check here for more info on Logical Processing Order of the SELECT statement
ROW_NUMBER() cannot be used with same query. Make ORDER BY in outer query.
EDIT : You cannot use rownr in the same query since you are computing ROW_NUMBER() in one place. You can access rownr in an outer query.
SELECT * FROM
(
SELECT col1,col2,unit,
ROW_NUMBER() OVER(PARTITION BY col2 ORDER BY col2) as rownr
FROM table1 t1 WITH(NOLOCK)
JOIN table2 t2 WITH(NOLOCK) ON t2.id = t1.id
)TAB
WHERE rownr > 1
ORDER BY rownr,unit
I want to INSERT INTO by more than one value at a time, I did this by doing the following:
INSERT INTO table_1(col_1,col_2,col_3)
SELECT col_1, col2, (SELECT col3 FROM table_3)
FROM table_2
But col3 from table_3 is a datetime format, while col3 from table_1 needs an integer value. I did this by doing the following:
CAST(CONVERT(varchar(10),(SELECT col3 FROM table_3),112)AS int)
When I run this I get a more than one result in a subquery error. I have really no idea whatsoever on how to fix this. Hopefully you do.
Thank you in advance.
INSERT INTO table_1(col_1,col_2,col_3)
SELECT col_1, col2, (CAST(CONVERT(varchar(10),(SELECT top 1 col3 FROM table_3),112)AS int))
FROM table_2
You need to use top 1 to select 1 row
Well, I think the error says it all. You have to limit the inner query somehow with WHERE condition, with TOP or with MAX(col3) for example. Depends WHICH col3 you want.
You need to join table_2 to table_3. Not sure what your database structure is, but it should be something like this:
INSERT INTO table_1(col_1,col_2,col_3)
SELECT t2.col_1, t2.col2, t3.col3
FROM table_2 t2
INNER JOIN table_3 t3 on t3.t2id = t2.id
The alternative is to use TOP 1, to just return 1 record in the sub-query - but I would not recommend this as it may not be the value you want:
INSERT INTO table_1(col_1,col_2,col_3)
SELECT col_1, col2, (SELECT top 1 col3 FROM table_3)
FROM table_2
You can use CTE to prepare your data :
;WITH MyData (col1, col2, col3)
AS
(
SELECT col_1, col2, CAST(CONVERT(varchar(10),(col3),112)AS int)
FROM table_2 JOIN table_3 ON <join condition>
)
INSERT INTO table_1(col_1,col_2,col_3)
SELECT col_1, col2, col3
FROM MyData
Pls try below query :
INSERT INTO table_1(col_1,col_2,col_3)
SELECT col_1, col2, isnull((SELECT TOP 1 cast(col3 as int) FROM table_3),0)
FROM table_2
I have a SQL Select and I am not sure how I can achieve this. I am checking two fields to see if any of those fields are in a list. So like,
Select * from MyTable where col1 or col2 in (select col3 from OtherTable where ID=1)
I tried
Select * from MyTable where
col1 in (select col3 from OtherTable where ID=1)
or col2 in (select col3 from OtherTable where ID=1)
But, this returns the records that match first condition (only returns col1, but not col2) for some reasons.
Try this -
Select * from MyTable where
(col1 in (select col3 from OtherTable where ID=1))
or
(col2 in (select col3 from OtherTable where ID=1) )
if you're subquery is the same for both columns, i'd throw it into a cte, then do a left outer join on the cte on col1 and col2, then do your where statement.
;with c3 as
(
select col3
from OtherTable
where ID=1
)
select m.*
from MyTable m
left outer join c3 as c1
on m.col1=c1.col3
left outer join c3 as c2
on m.col2=c2.col3
where
(c1.col3>'')
or (c2.col3>'')
if a blank varchar that isn't null is a viable option, change your where clauses to >=.
SELECT t.*
FROM MyTable t
INNER JOIN (
select col3
from OtherTable
where ID=1
) sel ON sel.col3 IN (t.col1, t.col2)