Problem combining result of two different queries into one - sql

I have two tables (TableA and TableB).
create table TableA
(A int null)
create table TableB
(B int null)
insert into TableA
(A) values (1)
insert into TableB
(B) values (2)
I cant join them together but still I would like to show the result from them as one row.
Now I can make select like this:
select
(select A from tableA) as A
, B from TableB
Result:
A B
1 2
But if I now delete from tableB:
delete tableB
Now when I run the same query as before:
select
(select A from tableA) as A
, B from TableB
I see this:
A B
But I was expecting seeing value from tableA
like this:
Expected Result:
A B
1
Why is this happening and how can I still see the value from TableA although selectB is returning 0 rows?
I am using MS SQL Server 2005.

Use a LEFT JOIN (although it's more of a cross join in your case).
If your db supports it:
SELECT a.a, b.b
FROM a
CROSS JOIN b
If not, do something like:
SELECT a.a, b.b
FROM a
LEFT JOIN b ON ( 1=1 )
However, once you have more rows in a or b, this will return the cartesian product:
1 1
1 2
2 1
2 2

This will actually give you what you're looking for, but if you only have one row per table:
select
(select A from tableA) as A
, (select B from TableB) as B

give this a try:
DECLARE #TableA table (A int null)
DECLARE #TableB table (B int null)
insert into #TableA (A) values (1)
insert into #TableB (B) values (2)
--this assumes that you don't have a Numbers table, and generates one on the fly with up to 500 rows, you can increase or decrease as necessary, or just join in your Numbers table instead
;WITH Digits AS
(
SELECT 0 AS nbr
UNION SELECT 1 UNION SELECT 2 UNION SELECT 3
UNION SELECT 4 UNION SELECT 5 UNION SELECT 6
UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
)
, AllNumbers AS
(
SELECT u3.nbr * 100 + u2.nbr * 10 + u1.nbr + 1 AS Number
FROM Digits u1, Digits u2, Digits u3
WHERE u3.nbr * 100 + u2.nbr * 10 + u1.nbr + 1 <= 500
)
, AllRowsA AS
(
SELECT
A, ROW_NUMBER() OVER (ORDER BY A) AS RowNumber
FROM #TableA
)
, AllRowsB AS
(
SELECT
B, ROW_NUMBER() OVER (ORDER BY B) AS RowNumber
FROM #TableB
)
SELECT
a.A,b.B
FROM AllNumbers n
LEFT OUTER JOIN AllRowsA a on n.Number=a.RowNumber
LEFT OUTER JOIN AllRowsB b on n.Number=b.RowNumber
WHERE a.A IS NOT NULL OR b.B IS NOT NULL
OUTPUT:
A B
----------- -----------
1 2
(1 row(s) affected)
if you DELETE #TableB, the output is:
A B
----------- -----------
1 NULL
(1 row(s) affected)

try this:
select a, (select b from b) from a
union
select b, (select a from a) from b
should retrieve you all the existing data.
you can filter it more by surrounding it with another select

Related

How to get the records of table A, which are in one row in table B

SELECT ClaimID, CPTCode FROM TABLEA
ClaimId CPTCode
**60 62000**
**60 0213T**
60 99383
60 93230
60 96372
SELECT cpt1,CPT2 FROM TABLEB
cpt1 CPT2
**62000 0213T**
**62000 0230T**
62000 0216T
62000 0228T
SELECT the record from tableA only that which is at same row in tableB
Result should be
60 62000
60 0213T
I think this does what you want:
select ClaimID, CPTCode
from tablea a
where exists (select 1
from tableb b
where b.cpt1 = a.cptcode
) or
exists (select 1
from tableb b
where b.cpt2 = a.cptcode
);
This query can take advantage of two indexes: tableb(cpt1) and tableb(cpt2).
You can write this as:
select ClaimID, CPTCode
from tablea a
where exists (select 1
from tableb b
where a.cptcode in (b.cpt1, b.cpt2)
);
However, this version is much harder to optimize.
try this-
select obj.ClaimID, obj.CPTCode from (
select row_number() as row_noA, ClaimID, CPTCode FROM TABLEA
join
select row_number() as row_noB, cpt1,CPT2 FROM TABLEB
on TABLEA.CPTCode = TABLEB.CPT2 and TABLEA.row_noA = TABLEB.row_noB
)obj
join two tables and match each row using same row number and get the output

SQL joining on >=

I have a table like this in ORACLE
a b
-- --
1000 1
100 2
10 3
1 4
My other table has numbers like '67' or '112' in a column called numbers for example.
How can I join to this table using those values and get the correct result where >=1000 would be 1 and >= 100 would be 2 >=10 would be 3 etc.
I tried to do a
select g.b
from table o
join table2 g on o.column >= g.a
when I do this say 1002 was the value of g I would get the back these results.
1
2
3
4
when I just want 1
Easiest would be if your lookup table had ranges instead of just one number, such as row 1 = 1000,9999,1 and row 2 = 100,999,2 etc.
Then your join might be
SELECT OtherTable.n, lookup.b
from OtherTable
LEFT JOIN lookup on OtherTable.n between lookup.low and lookup.high
But, if you really want to use your original table, then on SQL Server, do this:
/*CREATE TABLE #A (a int,b int)
INSERT INTO #A VALUES (1000,1),(100,2),(10,3),(1,4)
CREATE TABLE #B (n INT)
INSERT INTO #B VALUES (67),(112),(4),(2001)
*/
SELECT B.n, A1.b
FROM #B B OUTER APPLY (SELECT TOP 1 a,b FROM #A A WHERE A.a<B.n ORDER BY A.a DESC) A1
Here's one way to do it using a subquery to get the MAX of column a, and then rejoining on the same table to get b:
select t.numericvalue, t2.b
from (
select t.numericvalue, max(t2.a) maxb
from table1 t
join table2 t2 on t.numericvalue >= t2.a
group by numericvalue
) t join table2 t2 on t.maxb = t2.a
SQL Fiddle Demo

SQL Server - Providing priority to where clause condtions

Please consider the following SQL.
declare #t1 table(site int, id int, name varchar(2))
declare #t2 table(site int, id int, mark int)
insert into #t1
select 1,1,'A'
union select 1,2,'B'
union select 1,3,'C'
union select 2,2,'D'
union select 2,3,'C'
insert into #t2
select 1,1,10
union select 1,2,20
union select 0,3,30
union select 1,3,40
union select 2,3,40
union select 2,3,40
select distinct a.site, a.id,a.name,b.mark
from #t1 a
inner join #t2 b
on (a.site =b.site or b.site = 0) and a.id = b.id
where a.site=1
It produces the following result
site id name mark
----------------------------
1 1 A 10
1 2 B 20
1 3 C 30
1 3 C 40
It's correct.
But I want a person's data exactly once. The SQL should first check whether there is an entry for a person in #t2 for a specific site. If entry is found, then use it. If not, the mark of that person will be the person's mark who has the same name in site 0.
In this case, I want the result as follows.
site id name mark
----------------------------
1 1 A 10
1 2 B 20
1 3 C 40
But if (1,3,40) isn't in #t2, The result should be as follows.
site id name mark
----------------------------
1 1 A 10
1 2 B 20
1 3 C 30
How can I do this?
I can do it using Common Table Expression.
So please provide me a faster way.
I'll run it on about 100 millions rows.
You can roll all of the conditions into the on clause:
declare #target_site as Int = 1
select distinct a.site, a.id, a.name, b.mark
from #t1 as a inner join
#t2 as b on a.site = #target_site and a.id = b.id and
( a.site = b.site or ( b.site = 0 and not exists ( select 42 from #t2 where site = #target_site and id = a.id ) ) )
Outer Join to the t2 table twice, and Use a subquery to ensure that only records that have a match or are zeroes are included.
Select distinct a.site, a.id, a.name,
coalesce(sm.mark, zs.mark) mark
from #t1 a
Left Join #t2 sm -- for site match
on sm.id = a.id
And sm.site = a.site
Left Join #t2 zs -- for zero site
on zs.id = a.id
And zs.site = 0
Where Exists (Select * From #t2
Where id = a.id
And Site In (a.Site, 0))
And a.site=1

CTE to recurse to root in Table A, and join results from Table B at each iteration

I'm new to CTE's in T-SQL but am loving them. However, I cannot get the logic right for this particular stored procedure I'm writing.
Given Table A with the columns:
Id Name Inherits ...
Where the column Inherits stores an int that is an id to another row in this same table.
And Table B with the columns:
Id Name AId ...
Where AId is a foreign key to a row in Table A.
How could one use a CTE to start from an arbitrary row (x) in A, collect all rows in B where AId = x.Id, and then recurse upwards in A by setting x to the row pointed to by x.Inherits. This should proceed until x.Inherits IS NULL.
So the overall effect is I want to return the related B rows for the starting A Id, and then all inherited B rows that we discover by examining the Inherits column of A recursively.
My thinking is to set up the CTE to recurse to the 'root' of A from an arbitrary row, and inside each recursive call have a JOIN to B. This is as far as I've got:
WITH c
AS
(
SELECT A.Inherits,A.Id, B.Name, 1 AS Depth
FROM tbl_A A
INNER JOIN tbl_B B ON B.AId = A.Id
WHERE A.Id = #ArbitraryStartingAId
UNION ALL
SELECT T.Inherits,T.Id, c.Name, c.Depth + 1 AS 'Level'
FROM tbl_A T
INNER JOIN c ON T.Id = c.Inherits
)
SELECT *
FROM c
Which produces:
1 4 b_val 1
11 1 b_val 2
NULL 11 b_val 3
Where b_val is taken from a Table B row (y) where #ArbitraryStartingAId = y.AId. The recursion on A is working, but not pulling in the correct corresponding B data upon each iteration.
If someone could help rewrite this to yield the results I need then that would be great.
Many thanks
Supposing we have
CREATE TABLE A ( Id int, Name nvarchar(10), Inherits int );
CREATE TABLE B ( Id int, Name nvarchar(10), AId int );
And some data:
INSERT A VALUES ( 1, 'one', 2 );
INSERT A VALUES ( 2, 'two', 3 );
INSERT A VALUES ( 3, 'three', null );
INSERT A VALUES ( 4, 'four', 3 );
INSERT B VALUES ( 1, 'B one', 1 );
INSERT B VALUES ( 2, 'B two', 2 );
INSERT B VALUES ( 3, 'B three', 3 );
INSERT B VALUES ( 4, 'B four', 4 );
We can build a CTE on A, and then join to B:
WITH cteA AS
(
-- Anchor
SELECT Id, Name, Inherits FROM A
WHERE Id = 1
UNION
-- Recursive
SELECT A.Id, A.Name, A.Inherits FROM A
INNER JOIN cteA ON A.Id = cteA.Inherits
)
SELECT * FROM cteA INNER JOIN B ON cteA.Id = B.AId;
to get (with the anchor at 1):
Id Name Inherits Id Name AId
----------- ---------- ----------- ----------- ---------- -----------
1 one 2 1 B one 1
2 two 3 2 B two 2
3 three NULL 3 B three 3
Here's where I'm at now and it's one possible answer as the correct data is returned:
WITH c
AS
(
SELECT A.Inherits,A.Id, B.Name, 1 AS Depth
FROM tbl_A A
INNER JOIN tbl_B B ON B.AId = A.Id
WHERE A.Id =#ArbitraryStartingAId
UNION ALL
SELECT T.Inherits,T.Id, T.Name, B.Name, c.Depth + 1 AS 'Level'
FROM tbl_A T
INNER JOIN tbl_B B ON B.AId = T.Id
INNER JOIN c ON T.Id = c.Inherits
)
SELECT DISTINCT *
FROM c ORDER BY Depth ASC
It feels a bit dirty though as it returns the root level B rows twice, hence the DISTINCT operator to filter these out...??

SQL: Select lowest value that doesn't already exist

In TableA I have an int column.
Is it possible using only a select statement to select the minimum value in the column that DOES NOT EXIST and is greater then 0?
For example, if the col has the values 1,2,9 the select statement will return 3.
If the col has 9,10,11 it will return 1.
I can achieve this using a temp table or using a loop, but I'm wondering if I can do it using just a select statement?
SELECT MIN(t1.ID+1) as 'MinID'
FROM table t1 LEFT JOIN table t2
On t1.ID+1=t2.ID
Where t2.OtherField IS NULL
select
min(nt.id)
from numbertable nt
left outer join originaldata od
on nt.id=od.id
where od.id is null
have a number table that goes from 1 to your max value (or higher)
SELECT DISTINCT x + 1 "val"
EXCEPT SELECT DISTINCT x "val"
ORDER BY "val" ASC
LIMIT 1
What about this?
SELECT Min(id)
FROM (SELECT 1 id
FROM tablea
WHERE 1 NOT IN (SELECT id
FROM tablea)
UNION
SELECT id + 1 id
FROM tablea
WHERE id + 1 NOT IN (SELECT id
FROM tablea)) AS min_ids;
try this:(Updated)
declare #dummy varchar(10) ;
set #dummy =(select top(1) id from dbo.b)
if( #dummy= '1')
begin
select top(1)l.id + 1 as start
from dbo.b as l
left outer join dbo.b as r on l.id + 1 = r.id
where r.id is null
end
else
begin
select '1'
end
Give this a try:
declare #TestTable table (
col int
)
/* Test Case 1: 1,2,9 */
insert into #TestTable
(col)
select 1 union all select 2 union all select 9
SELECT MinValue = (SELECT ISNULL(MAX(t2.col),0)+1
FROM #TestTable t2
WHERE t2.col < t1.col)
FROM #TestTable t1
WHERE t1.col - 1 NOT IN (SELECT col FROM #TestTable)
AND t1.col - 1 > 0
delete from #TestTable
/* Test Case 2: 9,10,11 */
insert into #TestTable
(col)
select 9 union all select 10 union all select 11
SELECT MinValue = (SELECT ISNULL(MAX(t2.col),0)+1
FROM #TestTable t2
WHERE t2.col < t1.col)
FROM #TestTable t1
WHERE t1.col - 1 NOT IN (SELECT col FROM #TestTable)
AND t1.col - 1 > 0
I duplicated my answer from here:
SELECT MIN(a.id) + 1 AS firstfree
FROM (SELECT id FROM table UNION SELECT 0) a
LEFT JOIN table b ON b.id = a.id + 1
WHERE b.id IS NULL
This handles all cases I can think of - including no existing records at all.
The only thing I don't like about this solution is that additional conditions have to be included twice, like that:
SELECT MIN(a.id) + 1 AS firstfree
FROM (SELECT id FROM table WHERE column = 4711 UNION SELECT 0) a
LEFT JOIN table b ON b.column = 4711 AND b.id = a.id + 1
WHERE b.id IS NULL
Please also notice the comments about locking and concurrency - the requirement to fill gaps is in most cases bad design and can cause problems. However, I had a good reason to do it: the IDs are to be printed and typed by humans and we don't want to have IDs with many digits after some time, while all the low ones are free...