SQL query: finding a gap in a primary key - sql

How can I write a single select statement that does the following:
I have an integer column in my table and i want to find the minimum available (non-used) value in that column where the value is below 1000 and also where the value does not exist in TableB Column1
Thanks

Similar to LukeH's answer but it does what you asked for:
SELECT MIN(a.your_column) - 1 AS answer
FROM your_table AS a
LEFT JOIN your_table AS a2
ON a2.your_column = a.your_column - 1
LEFT JOIN tableB AS b
ON a.your_column = b.column1
WHERE a.your_column < 1000
AND b.column1 IS NULL
AND a2.your_column IS NULL
Edit:
UNION
SELECT MIN(a.your_column) + 1 AS answer
FROM your_table AS a
LEFT JOIN your_table AS a2
ON a2.your_column = a.your_column + 1
LEFT JOIN tableB AS b
ON a.your_column = b.column1
WHERE a.your_column < 1000
AND b.column1 IS NULL
AND a2.your_column IS NULL
And pick the minumum of the two values.
It still needs checking if the value 1 is available, but if you have a gap between A and B it should find A+1 and B-1 now and you could pick the smallest. Obviously A+1 is the smallest so you can just use the second part...

This results in 7, which I believe would be the correct answer given your criteria
CREATE TABLE #TableA (Value INT)
INSERT #TableA (Value) VALUES (1)
INSERT #TableA (Value) VALUES (2)
INSERT #TableA (Value) VALUES (3)
INSERT #TableA (Value) VALUES (5)
INSERT #TableA (Value) VALUES (6)
INSERT #TableA (Value) VALUES (8)
CREATE TABLE #TableB (Value INT)
INSERT #TableB (Value) VALUES (4)
SELECT MIN(A1.Value) + 1
FROM #TableA A1
LEFT JOIN #TableA A2 ON A2.Value = A1.Value + 1
LEFT JOIN #TableB B1 ON B1.Value = A1.Value + 1
WHERE A2.Value IS NULL
AND B1.Value IS NULL
AND A1.Value < 1000
DROP TABLE #TableA
DROP TABLE #TableB

Related

set value using a conditional of a subquery

Sorry if I am not explaining my issue the best, but basically I have two tables.
Table A has a reference column to table B. On table B there is column X where for each referenced row, there is an unreferenced row with that same value of column X (table B has double the rows of table A). I want to update the reference on table A to be the row of table B that is not currently referenced of the two rows that have the same value on column X.
In pseudo code...
update tableA
set refCol = (select tableB.refCol
from tableB
where colX = (select colX
from tableB
where tableB.refCol = tableA.refCol)
and tableB.refCol != tableA.refCol)
The innermost query returns two rows, the outer query returns one row
sample tables:
Table A
refCol
1
3
Table B
refCol
colX
1
hello
2
hello
3
hi
4
hi
expected output:
Table A
refCol
2
4
Any help would be much appreciated.
Refer it below working example
create table #tableA(
id int)
create table #tableB(
id int,
name varchar(10)
)
insert into #tableA values(1)
insert into #tableA values(3)
insert into #tableA values(5)
insert into #tableA values(6)
insert into #tableA values(7)
insert into #tableA values(8)
insert into #tableB values (1,'A')
insert into #tableB values (2,'A')
insert into #tableB values (3,'C')
insert into #tableB values (4,'C')
select * from #tableA
select * from #tableB
update aa set aa.id=ab.id from #tableA aa inner join (
select b.id,b.name,a.id as ta from (
select B.* from #tableB b left join #tableA a on a.id=b.id where a.id is null)b
inner join (
select b.* from #tableA a inner join #tableB b on a.id=b.id)a on a.name=b.name)ab on aa.id=ab.ta

JOIN tables based on 6 or 7 digits key in 1st table with 7 digits key in second table by using CASE and MAX function

Table 1:
Id1 Data1
123123 David
123124 Jan
1231344 Juro
1234126 Marco
Table 2:
Id2 Data2
1231230 Info 1
1231231 Info 2
1231232 Info 3
1231240 Info 4
1231241 Info 5
1231242 Info 6
Each id from Table 1 can have 1 or more matches in Table 2 based on first 6 digits.
For example 123123 from Table 1 matches 1231230, 1231231 and 1231232 in Table 2.
I'm trying to create join to match maximum id2 from Table 2 based on id1 from Table 1.
I would just join using LIKE:
SELECT
tb1.id1,
tb1.data1
MAX(tb2.[id2]) AS id2
FROM [dbo].[table1] tb1
LEFT JOIN [dbo].[table2] tb2
ON tb2.[id2] LIKE CONCAT(tb1.[id1], '%')
GROUP BY
tb1.id1,
tb1.data1
ORDER BY
tb1.id1 DESC;
This approach might still leave open the possibility of using an index on the second table. In any case, it is slightly easier to read than your version.
This is working solution:
SELECT tb1.*,
MAX(tb2.[id2]) as id2
FROM [dbo].[table1] tb1
LEFT JOIN [dbo].[table2] tb2
ON CASE
WHEN LEN(tb1.[id1]) = 7 and tb1.[id1] = tb2.[id2] THEN 1
WHEN LEN(tb1.[id1]) = 6 and tb1.[id1] = SUBSTRING(tb2.[id2],1,6) THEN 1
ELSE 0
END = 1
GROUP BY tb1.id1
,tb1.data1
ORDER BY tb1.id1 desc
You can try this as well:
Declare #t table (id1 varchar(50) , data1 varchar(50))
insert into #t values (123123,'David')
insert into #t values (123124,'Jan')
insert into #t values (1231344,'Juro')
Declare #t1 table (id2 varchar(50) , data2 varchar(50))
insert into #t1 values (1231230,'Info 1')
insert into #t1 values (1231231,'Info 2')
insert into #t1 values (1231232,'Info 3')
insert into #t1 values (1231240,'Info 4')
insert into #t1 values (1231241,'Info 5')
insert into #t1 values (1231242,'Info 6')
select * from #t a JOIN #t1 B
on b.id2 like '%' + a.id1 + '%'

Flag based on combination of variables

I have a table A which looks like below-
Column1 Column2
0001M 80050
0001M 80053
0001M 80076
0001T 0002T
0001T 34800
0001T 34802
0001T 34804
0001T 36000
0001U 80500
0001U 80502
0001U 81105
0001U 81106
CREATE TABLE mytable(
Column1 VARCHAR(5) NOT NULL PRIMARY KEY
,Column2 VARCHAR(5) NOT NULL
);
INSERT INTO mytable(Column1,Column2) VALUES ('0001M','80050');
INSERT INTO mytable(Column1,Column2) VALUES ('0001M','80053');
INSERT INTO mytable(Column1,Column2) VALUES ('0001M','80076');
INSERT INTO mytable(Column1,Column2) VALUES ('0001T','0002T');
INSERT INTO mytable(Column1,Column2) VALUES ('0001T','34800');
INSERT INTO mytable(Column1,Column2) VALUES ('0001T','34802');
INSERT INTO mytable(Column1,Column2) VALUES ('0001T','34804');
INSERT INTO mytable(Column1,Column2) VALUES ('0001T','36000');
INSERT INTO mytable(Column1,Column2) VALUES ('0001U','80500');
INSERT INTO mytable(Column1,Column2) VALUES ('0001U','80502');
INSERT INTO mytable(Column1,Column2) VALUES ('0001U','81105');
INSERT INTO mytable(Column1,Column2) VALUES ('0001U','81106');
I have another table B which has the following columns -
ID SubID
1 0001M
1 80050
1 80053
1 12500
2 0001T
2 0002T
2 34800
2 36000
2 12506
3 80500
3 80502
3 81106
CREATE TABLE mytable(
ID INTEGER NOT NULL PRIMARY KEY
,SubID VARCHAR(5) NOT NULL
);
INSERT INTO mytable(ID,SubID) VALUES (1,'0001M');
INSERT INTO mytable(ID,SubID) VALUES (1,'80050');
INSERT INTO mytable(ID,SubID) VALUES (1,'80053');
INSERT INTO mytable(ID,SubID) VALUES (1,'12500');
INSERT INTO mytable(ID,SubID) VALUES (2,'0001T');
INSERT INTO mytable(ID,SubID) VALUES (2,'0002T');
INSERT INTO mytable(ID,SubID) VALUES (2,'34800');
INSERT INTO mytable(ID,SubID) VALUES (2,'36000');
INSERT INTO mytable(ID,SubID) VALUES (2,'12506');
INSERT INTO mytable(ID,SubID) VALUES (3,'80500');
INSERT INTO mytable(ID,SubID) VALUES (3,'80502');
INSERT INTO mytable(ID,SubID) VALUES (3,'81106');
Both the values of column1 and column2 of tableA should not occur together in SubID column within each distinct ID column of tableB. If it happens, I need to flag it 1. Otherwise 0. For example, (0001M, 80050) and (0001M, 80053) are not allowed to occur together. Since these two combinations exist in ID=1 of table B, it should be flagged 1.
The output should like this -
ID Flag
1 1
2 1
3 0
Reason Flag = 0 for ID=3 --> Since (80500, 80502) and (80502, 81106) come from column2 only (not from both column 1 and 2), they are allowed to occur together, it is flagged 0. I am using SQL Server 2016 version.
select
b1.ID,
max(case
when exists (select 1 from tableA a where a.Column1=b1.SubId and a.Column2=b2.SubId)
then 1 else 0 end) as flag
from
tableB b1
inner join table B b2 on b1.ID=b2.ID
group by b1.ID
you can also use JOINS to get this done like below.
Logic is that if we get id in tableA from tableB for each column and they are same then flag should be 1
see live demo
select
distinct B.id, flag =case when b1.id = b2.id then 1 else NULL end
from
mytableA A
left join mytableB b1 on b1.subid=a.column1
left join mytableB b2 on b2.subid=a.column2
right join
mytableB B
on B.id= case when b1.id = b2.id then b1.id else NULL end
Hmmm . . . This is tricky. I think this does what you want.
select b.id,
(case when count(*) > 0 then 1 else 0 end) as flag
from (select distinct b.id from b) b cross join
a join
b b1
on b1.subid = a.column1 and b1.id = b.id join
b b2
on b2.subid = a2.column2 and b2.id = b.id
group by b.id;

Get records which are not in tables when passed in In clause?

I am sure that the title of the question need to get change , but not sure what to put from my end .
I am passing In clause in two Tables want to get the records which are not in both the tables .
Table A contains ID 1,2
Table B contains ID 3,4
I am passing in my In clause (1,2,3,4,5,6)
I am looking for Something
1 TableA
2 TableA
3 TableB
4 TableB
5 Not Found
6 Not Found
I am using union all to get items from Table A and Table B not sure how to get the not found records in both the table ?
Here is one method. It uses exists to check whether the tables contain the id:
select id,
(case when inA = 1 and inB = 1 then 'Both'
when inA = 1 then 'TableA'
when inB = 1 then 'TableB'
else 'Not Found'
end) as status
from (select id,
(case when exists (select 1 from tableA a where a.id = ids.id then 1 else 0 end) as inA,
(case when exists (select 1 from tableB b where b.id = ids.id then 1 else 0 end) as inB
from (values (1), (2), (3), (4), (5), (6)) as ids(id)
) i;
Of course, you can add where inA = 0 or inB = 0 if you don't want the 'Both' rows.
Try following query:
DECLARE #TableA TABLE (Col1 INT)
INSERT #TableA VALUES (1), (2),(5)
DECLARE #TableB TABLE (Col2 INT)
INSERT #TableB VALUES (3), (4),(5)
-- Query
SELECT t.Col3,
CONCAT(xa.ExistsInA, ',', xb.ExistsInB) AS SourceTables
--STUFF(CONCAT(',' + xa.ExistsInA, ',' + xb.ExistsInB), 1, 1, '') AS SourceTables
FROM (VALUES
(1),
(2),
(3),
(4),
(5),
(6)
) AS t(Col3)
OUTER APPLY (
SELECT 'TableA'
WHERE EXISTS(SELECT * FROM #TableA a WHERE a.Col1 = t.Col3)
) xa (ExistsInA)
OUTER APPLY (
SELECT 'TableB'
WHERE EXISTS(SELECT * FROM #TableB b WHERE b.Col2 = t.Col3)
) xb (ExistsInB)

Combine 2 query output in one result set

I have two query output as follow-
Query-1 Output:
A
B
C
Query-2 Output:
1
2
3
4
5
Now I am looking forward to join these two outputs that will return me the following output-
Combine Output:
A | 1
B | 2
C | 3
NULL | 4
NULL | 5
Note: There is no relation between the output of Query 1 & 2
Thanks in advance, mkRabbani
The relation is based on the order of the values from table A and B, so we LEFT JOIN the results from A (containing the numbers) to the results from B (containing the characters) on the ordered index.
DECLARE #a TABLE (col int);
DECLARE #b TABLE (col char(1));
INSERT INTO #a VALUES (1);
INSERT INTO #a VALUES (2);
INSERT INTO #a VALUES (3);
INSERT INTO #a VALUES (4);
INSERT INTO #a VALUES (5);
INSERT INTO #b VALUES ('A');
INSERT INTO #b VALUES ('B');
INSERT INTO #b VALUES ('C');
SELECT B.col, A.col
FROM ( SELECT col, ROW_NUMBER() OVER(ORDER BY col) AS RowNum FROM #a ) AS A
LEFT JOIN ( SELECT col, ROW_NUMBER() OVER(ORDER BY col) AS RowNum FROM #b ) AS B ON A.RowNum = B.RowNum
You can get the desired result by using Row_Number() and full outer join.
Please check the SQLFiddler, in which I have reproduced the desired result.
http://sqlfiddle.com/#!3/21009/6/0
Create Table T1 (col1 nVarchar(10))
Go
Create Table T2 (col1 nvarchar(10))
Go
Insert T1 (col1) Values ('A'), ('B'), ('C')
Insert T2 (col1) Values ('1'), ('2'), ('3'), ('4'), ('5')
Go
;With CTE1 As (
Select col1,
Row_Number() Over(Order By Col1) Rn
From T1
), CTE2 As (
Select col1,
Row_Number() Over(Order By Col1) Rn
From T2
)
Select CTE1.col1, CTE2.col1 From CTE1 Right Outer Join
CTE2 On CTE1.Rn = CTE2.Rn