Condition on two fields - sql-server

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)

Related

Rewrite correlated subquery to CROSS APPLY

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

SQL: Delete only one row if join returns multiple matches

I have an SQL table that looks as follows:
col1 col2
a b
b a
c d
d c
f g
As you can see there are rows where both columns col1 and col2 are inverted. What I mean is that in the first row the values a and b are in both columns and in row 2 the values are also there, but the other way round.
I now want to delete one row of each of these pairs. I do not care which side of the pair is deleted. So either row 1 and row 3 or row 2 and row 4 should be deleted.
The result should looks as follows:
col1 col2
a b
c d
f g
or
col1 col2
b a
d c
f g
I achieved this with the following query that creates two artificial columns that contain the values in a sorted order and then applies a GROUP BY, but I assume there should be a nicer looking solution.
DELETE t1
FROM testtable t1
INNER JOIN (
SELECT CASE WHEN col1 < col2 THEN col1 ELSE col2 END AS first,
CASE WHEN col1 < col2 THEN col2 ELSE col1 END AS second
FROM testtable
GROUP BY CASE WHEN col1 < col2 THEN col1 ELSE col2 END, CASE WHEN col1 < col2 THEN col2 ELSE col1 END
) t2 ON t2.first = t1.col1 AND t2.second = t1.col2
I think you can simplify your query by adding conditions to the join:
DELETE T1
FROM #testable T1
INNER JOIN #testable T2 ON T1.col1 = T2.col2 AND T1.col2 = T2.col1 AND T1.col1 > T1.col2
You can use exists & not exists :
select t.*
from testtable t
where exists (select 1
from testtable t1
where t1.col1 > t.col1 and t1.col1 = t.col2
) or
not exists (select 1
from testtable t1
where t1.col1 < t.col1 and t1.col1 = t.col2
);
If you want to remove unwanted records then you can do :
delete t
from testtable t
where not exists (select 1
from testtable t1
where t1.col1 > t.col1 and t1.col1 = t.col2
) and
exists (select 1
from testtable t1
where t1.col1 < t.col1 and t1.col1 = t.col2
);
Assuming no actual duplicates, I would do:
delete t from testtable t
where col1 > col2 and
exists (select 1
from testtable t2
where t2.col1 = t.col2 and t2.col2 = t.col1
);
That is, delete the rows where col1 > col2 but only if the "paired" row already exists in the table.

TSQL display field values for column with count column in condition

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

how to apply policy on multiple match in MSSQL

create table a ( col1 int, col2 int)
create table b (col1 int,col2 int)
insert b
select 1,2
union
select 1,2
insert a
select 1,2
union
select 2,2
Expected o/p (need to join two tables and then get true for first match, false for second match and if not match also false)
1,2,T
1,2,F
2,2,F
SELECT col1, col2,
CASE WHEN (rownumber = 1 AND othercol is not null)
THEN 'T' ELSE 'F' END col3
FROM
(
Select a.col1, a.col2,b.col1 othercol, ROW_NUMBER() OVER(Partition by a.col1 ,a.col2 order by a.col1,a.col2) rownumber
from #a a
LEFT JOIN #b b ON a.col1 = b.col1 AND a.col2 = b.col2
) t

INSERT INTO multiple rows with subquery

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

Resources