Flag based on combination of variables - sql

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;

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 + '%'

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

SQL query: finding a gap in a primary key

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

SQL script to aggregate column values

i'd appreciate some help putting together a sql script to copy data from one table to another. essentially what i need to do for each row in the source table is aggregate the column values and store them into a single column in the target table.
TableA: ID, ColumnA, ColumnB, ColumnC
TableB: Identity, ColumnX
so, ColumnX needs to be something like 'ColumnA, ColumnB, ColumnC'.
in addition though, i need to keep track of each TableA.ID -> SCOPE_IDENTITY() mapping in order to update a third table.
thanks in advance!
EDIT: TableA.ID is not the same as TableB.Identity. TableB.Identity will return a new identity value on insert. so either i need to store the mapping in a temp table or update TableC with each insert into TableB.
Here is a row-by-row processing example. This will provide you the results in a way where you can process each row at a time. Or you can use TableC at the end and do whatever processing you need to do.
However, it would be a lot faster if you added an extra column to TableB (Called TableA_ID) and just INSERTED the result into it. You would have instant access to TableA.ID and TableB.Identity. But without knowing your exact situation, this may not be feasible. (But you could always add the column and then drop it afterwards!)
USE tempdb
GO
CREATE TABLE TableA (
ID int NOT NULL PRIMARY KEY,
ColumnA varchar(10) NOT NULL,
ColumnB varchar(10) NOT NULL,
ColumnC varchar(10) NOT NULL
)
CREATE TABLE TableB (
[Identity] int IDENTITY(1,1) NOT NULL PRIMARY KEY,
ColumnX varchar(30) NOT NULL
)
CREATE TABLE TableC (
TableA_ID int NOT NULL,
TableB_ID int NOT NULL,
PRIMARY KEY (TableA_ID, TableB_ID)
)
GO
INSERT INTO TableA VALUES (1, 'A', 'A', 'A')
INSERT INTO TableA VALUES (2, 'A', 'A', 'B')
INSERT INTO TableA VALUES (3, 'A', 'A', 'C')
INSERT INTO TableA VALUES (11, 'A', 'B', 'A')
INSERT INTO TableA VALUES (12, 'A', 'B', 'B')
INSERT INTO TableA VALUES (13, 'A', 'B', 'C')
INSERT INTO TableA VALUES (21, 'A', 'C', 'A')
INSERT INTO TableA VALUES (22, 'A', 'C', 'B')
INSERT INTO TableA VALUES (23, 'A', 'C', 'C')
GO
-- Do row-by-row processing to get the desired results
SET NOCOUNT ON
DECLARE #TableA_ID int
DECLARE #TableB_Identity int
DECLARE #ColumnX varchar(100)
SET #TableA_ID = 0
WHILE 1=1 BEGIN
-- Get the next row to process
SELECT TOP 1
#TableA_ID=ID,
#ColumnX = ColumnA + ColumnB + ColumnC
FROM TableA
WHERE ID > #TableA_ID
-- Check if we are all done
IF ##ROWCOUNT = 0
BREAK
-- Insert row into TableB
INSERT INTO TableB (ColumnX)
SELECT #ColumnX
-- Get the identity of the new row
SET #TableB_Identity = SCOPE_IDENTITY()
-- At this point, you have #TableA_ID and #TableB_Identity.
-- Go to town with whatever extra processing you need to do
INSERT INTO TableC (TableA_ID, TableB_ID)
SELECT #TableA_ID, #TableB_Identity
END
GO
SELECT * FROM TableC
GO
SELECT * FROM TableA
ID ColumnA ColumnB ColumnC
----------- ---------- ---------- ----------
1 A A A
2 A A B
3 A A C
11 A B A
12 A B B
13 A B C
21 A C A
22 A C B
23 A C C
SELECT * FROM TableB
Identity ColumnX
----------- ------------------------------
1 AAA
2 AAB
3 AAC
4 ABA
5 ABB
6 ABC
7 ACA
8 ACB
9 ACC
SELECT * FROM TableC
TableA_ID TableB_ID
----------- -----------
1 1
2 2
3 3
11 4
12 5
13 6
21 7
22 8
23 9
Assuming:
TableB exists
INSERT INTO TableB (ColumnX)
SELECT [TableA]![ColumnA]+","+[TableA]![ColumnB]+","+[TableA]![ColumnC] AS ColumnX
FROM TableA;