how to apply policy on multiple match in MSSQL - sql-server

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

Related

Replacing a single column with randomly selected values from another table

I found some solutions to replace (below example) #test.col2 with data from #test2.src. But in the result it just selects a single random value and replaces them all with it. How to fix? Thanks!
#test (the target table)
col1 col2
-------------
A 1
B 2
C 3
D 4
E 5
#test2 (the source table)
src1
sample1
sample2
sample3
Query:
UPDATE #test
SET col1 = data1.LastName
FROM #test
CROSS APPLY
(SELECT TOP(1) #test2.LastName
FROM #test2
ORDER BY NEWID()) data1
Example result:
col1 col2
----------------
A sample2
B sample2
C sample2
D sample2
E sample2
Here is one way to tackle this. It is using ROW_NUMBER in a cte to "randomize" the values.
if OBJECT_ID('tempdb..#test') is not null
drop table #test;
create table #test
(
col1 varchar(20)
, col2 int
);
insert #test
select 'A', 1 union all
select 'B', 2 union all
select 'C', 3 union all
select 'D', 4 union all
select 'E', 5;
if OBJECT_ID('tempdb..#test2') is not null
drop table #test2;
create table #test2
(
LastName varchar(20)
);
insert #test2
select 'src1' union all
select 'sample1' union all
select 'sample2' union all
select 'sample3';
--here is the data before any updates
select * from #test;
with t1 as
(
select col1
, col2
, RowNum = ROW_NUMBER() over(order by newid())
from #test
)
, t2 as
(
select LastName
, RowNum = ROW_NUMBER() over(order by newid())
from #test2
)
update t
set col1 = t2.LastName
from t1
join t2 on t1.RowNum = t2.RowNum
join #test t on t.col1 = t1.col1
--we now have updated with a "random" row
select * from #test;

How to create a nullable record in SQL Server 2008 R2?

I create a Inline table function in SQL Server 2008 R2, and I realized some queries return any record. So I'd like when that happens, returns a record with all the empty columns.
By example:
Col1 Col2 Col3
NULL NULL NULL
UPDATE: Here is the function
ALTER FUNCTION [dbo].[GetWorksheetSummaryByObjective](#objectiveId [smallint], #testTemplateId [smallint])
RETURNS #resultTable TABLE (
[AnsweredWorksheetId] [smallint] NOT NULL,
[LastDate] [date] NULL,
[BestScore] [smallint] NULL,
[ShouldBeMakeUp] [tinyint] NOT NULL
)
AS
BEGIN
INSERT #resultTable
SELECT TOP 1 B.Id AS AnsweredWorksheetId, A.Date, CONVERT(smallint, B.Score * 100),
CASE
WHEN B.Score >= 0.7 THEN 0
ELSE 1
END AS ShouldBeMakeUp
FROM AnsweredTest AS A
RIGHT JOIN AnsweredWorksheet AS B ON (A.Id = B.AnsweredTestId)
WHERE B.ObjectiveId = #objectiveId AND A.ExamTemplateId = #testTemplateId
ORDER BY B.Score DESC
RETURN
END
The function you have posted is a not an inline TVF.
Given that the underlying query returns at most 1 row because of the TOP 1 and SELECT MAX() without a GROUP BY or HAVING always returns a single row you could do this as an inline TVF however as below.
CREATE FUNCTION [dbo].[Getworksheetsummarybyobjective](#objectiveId [SMALLINT],
#testTemplateId [SMALLINT])
RETURNS TABLE
AS
RETURN
(SELECT Max(AnsweredWorksheetId) AS AnsweredWorksheetId,
Max([LastDate]) AS [LastDate],
Max([BestScore]) AS [BestScore],
Max(ShouldBeMakeUp) AS ShouldBeMakeUp
FROM (SELECT TOP 1 B.Id AS AnsweredWorksheetId,
A.Date AS [LastDate],
CONVERT(SMALLINT, B.Score * 100) AS [BestScore],
CASE
WHEN B.Score >= 0.7 THEN 0
ELSE 1
END AS ShouldBeMakeUp
FROM AnsweredTest AS A
RIGHT JOIN AnsweredWorksheet AS B
ON ( A.Id = B.AnsweredTestId )
WHERE B.ObjectiveId = #objectiveId
AND A.ExamTemplateId = #testTemplateId
ORDER BY B.Score DESC) T)
Would something like this work?
declare #tbl table
(
Col1 int, Col2 int, Col3 int
)
insert #tbl (Col1, Col2, Col3)
select Col1, Col2, Col3 from SomeTable where blah = blah
if exists (select 1 from #tbl)
begin
select Col1, Col2, Col3 from #tbl
end
else
begin
select null Col1, null Col2, null Col3
end
Ok, skip my other answer - didn't realize how restrictive table functions were. I've got another thought - this one should work, but it means having to run the WHERE twice in the function, so double the resources to make the call:
CREATE FUNCTION dbo.SomeTest
( #i int )
RETURNS TABLE
as
RETURN
select Col1, Col2 from SomeTable
where Whatever = Whatever
union all
select null Col1, null Col2
where not exists (select 1 from SomeTable where Whatever = Whatever)
go
EDIT: Thought of another way to do this without the double-dipping:
create function dbo.SomeTest
( #i int )
returns table
as
return
select t.Col1, t.Col2 from
(
select Col1, Col2
from SomeTable
where Whatever = Whatever
) t
right join
(
select 1 testcol
) x on c.Col1 is not null
go
This assumes that Col1 is a non-null column.

Combine two tables in SQL Server

I have tow tables with the same number of rows
Example:
table a:
1,A
2,B
3,C
table b:
AA,BB
AAA,BBB,
AAAA,BBBB
I want a new table made like that in SQL SErver:
1,A,AA,BB
2,B,AAA,BBB
3,C,AAAA,BBBB
How do I do that?
In SQL Server 2005 (or newer), you can use something like this:
-- test data setup
DECLARE #tablea TABLE (ID INT, Val CHAR(1))
INSERT INTO #tablea VALUES(1, 'A'), (2, 'B'), (3, 'C')
DECLARE #tableb TABLE (Val1 VARCHAR(10), Val2 VARCHAR(10))
INSERT INTO #tableb VALUES('AA', 'BB'),('AAA', 'BBB'), ('AAAA', 'BBBB')
-- define CTE for table A - sort by "ID" (I just assumed this - adapt if needed)
;WITH DataFromTableA AS
(
SELECT ID, Val, ROW_NUMBER() OVER(ORDER BY ID) AS RN
FROM #tablea
),
-- define CTE for table B - sort by "Val1" (I just assumed this - adapt if needed)
DataFromTableB AS
(
SELECT Val1, Val2, ROW_NUMBER() OVER(ORDER BY Val1) AS RN
FROM #tableb
)
-- create an INNER JOIN between the two CTE which just basically selected the data
-- from both tables and added a new column "RN" which gets a consecutive number for each row
SELECT
a.ID, a.Val, b.Val1, b.Val2
FROM
DataFromTableA a
INNER JOIN
DataFromTableB b ON a.RN = b.RN
This gives you the requested output:
You could do a rank over the primary keys, then join on that rank:
SELECT RANK() OVER (table1.primaryKey),
T1.*,
T2.*
FROM
SELECT T1.*, T2.*
FROM
(
SELECT RANK() OVER (table1.primaryKey) [rank], table1.* FROM table1
) AS T1
JOIN
(
SELECT RANK() OVER (table2.primaryKey) [rank], table2.* FROM table2
) AS T2 ON T1.[rank] = T2.[rank]
Your query is strange, but in Oracle you can do this:
select a.*, tb.*
from a
, ( select rownum rn, b.* from b ) tb -- temporary b - added rn column
where a.c1 = tb.rn -- assuming first column in a is called c1
if there is not column with numbers in a you can do same trick twice
select ta.*, tb.*
from ( select rownum rn, a.* from a ) ta
, ( select rownum rn, b.* from b ) tb
where ta.rn = tb.rn
Note: be aware that this can generate random combination, for example
1 A AA BB
2 C A B
3 B AAA BBB
because there is no order by in ta and tb

Condition on two fields

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)

How to select from duplicate rows from a table?

I have the following table:
CREATE TABLE TEST(ID TINYINT NULL, COL1 CHAR(1))
INSERT INTO TEST(ID,COL1) VALUES (1,'A')
INSERT INTO TEST(ID,COL1) VALUES (2,'B')
INSERT INTO TEST(ID,COL1) VALUES (1,'A')
INSERT INTO TEST(ID,COL1) VALUES (1,'B')
INSERT INTO TEST(ID,COL1) VALUES (1,'B')
INSERT INTO TEST(ID,COL1) VALUES (2,'B')
I would like to select duplicate rows from that table. How can I select them?
I tried the following:
SELECT TEST.ID,TEST.COL1
FROM TEST WHERE TEST.ID IN
(SELECT ID
FROM TEST WHERE TEST.COL1 IN
(SELECT COL1
FROM TEST WHERE TEST.ID IN
(SELECT ID
FROM TEST
GROUP BY ID
HAVING COUNT(*) > 1)
GROUP BY COL1
HAVING COUNT(*) > 1)
GROUP BY ID
HAVING COUNT(*) > 1)
Where's the error? What do I need to modify?
And I would like it to show as:
ID COL1
---- ----
1 A
1 A
1 B
1 B
(4 row(s) affected)
SELECT id, col1
FROM Test
GROUP BY id, col1
HAVING COUNT(*) > 1
when you use
SELECT id, col1, COUNT(*) AS cnt
FROM Test
GROUP BY id, col1
HAVING COUNT(*) > 1
you practically have all duplicate rows and how often they appear. You can't identify them individually either way.
A slower way would be:
SELECT id, col1
FROM Test T
WHERE (SELECT COUNT(*)
FROM Test I
WHERE I.id = T.id AND I.col1 = T.col1) > 1
Using Sql Server 2005+ and CTE you could try
;WITH Dups AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY ID, Col1 ORDER BY ID, Col1) Rnum
FROM #TEST t
)
SELECT *
FROM Dups
WHERE Rnum > 1
OR just a standard
SELECT ID,
Col1,
COUNT(1) Cnt
FROM #TEST
GROUP BY ID,
Col1
HAVING COUNT(1) > 1
EDIT:
Display duplicate rows
SELECT t.*
FROM #Test t INNER JOIN
(
SELECT ID,
Col1,
COUNT(1) Cnt
FROM #TEST
GROUP BY ID,
Col1
HAVING COUNT(1) > 1
) dups ON t.ID = dups.ID
AND t.Col1 = dups.Col1
Every row in that set of data is a duplicate
select id, col1, count(*)
from test
group by id, col1
shows this
if you want to exclude the 2,B rows you need to do it explicitly
eg
SELECT id, col1
FROM Test
WHERE NOT (id = 2 and col1 = 'B')
SELECT t.*
FROM TEST t
INNER JOIN (
SELECT ID,COL1
from test
GROUP BY ID,COL1
HAVING COUNT(*) > 1
)
AS t2
ON t2.ID = t.ID AND t2.COL1 =t.COL1
order by t.ID,t.COL1

Resources