Select from two tables as one table - sql-server

I don't know if it is possible or not. If possible, please help me to resolve this.
I have two tables, table1 and table2
Table1 Table2
CashReceivedFrom Amount CashPaidOutto Amount
x 100 A 300
Y 200 B 400
z 250
xy 300
There is no relation between table1 and table2. I want to execute a query so that my output looks like this:
Output table
CashReceivedFrom Amount CashPaidOutto Amount
x 100 A 300
Y 200 B 400
z 250
xy 300
I want to use it for a daily cash reprt

This gives you what you want.
CREATE TABLE #TMP1 (ID INT,Amnt INT)
CREATE TABLE #TMP2 (ID INT,Amnt INT)
INSERT INTO #TMP1 VALUES
(1,100)
,(2,130)
,(3,10)
,(4,160)
INSERT INTO #TMP2 VALUES
(76,1024)
,(78,134)
;WITH cteA
AS
(
SELECT *
,ROW_NUMBER() OVER(ORDER BY ID) AS Pos
FROM #TMP1
)
,cteB
AS
(
SELECT *
,ROW_NUMBER() OVER(ORDER BY ID) AS Pos
FROM #TMP2
)
SELECT
A.ID
,A.Amnt
,B.ID
,B.Amnt
FROM
cteA A
LEFT JOIN cteB B
ON
A.Pos = B.Pos

Try the below statement. I dont know why you need data with Null. But below snippet might be help you.
SELECT * FROM (
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1))
AS SNO, CASHRECIEVEDFROM, AMOUNT FROM TABLE1
) AS A
FULL OUTER JOIN
SELECT * FROM (
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1))
AS SNO, CASHPAIDTO, AMOUNT FROM TABLE2
) AS B ON A.SNO = B.SNO

Related

T-SQL Group by multiple batches of 2

So the wonderful people here on stackoverflow helped me with a "find consecutive failures" type query. (Status =4 is a failure). I thought I had cracked the second part of my problem because my test case seems to work fine but whenever I run it on our test environment I get dodgy results, so I must be doing something wrong. The goal is to find X number of consecutive failures. So the below is set to find 2 consecutive failures. I'm using SQL Server 2008 R2
DECLARE #t TABLE (
[InstructionId] INT,
[InstructionDetailId] INT,
[Sequence] INT,
[Status] INT
)
INSERT INTO #t SELECT 222,111,1, 2
INSERT INTO #t SELECT 222,112,2,2
INSERT INTO #t SELECT 222,113,3,4
INSERT INTO #t SELECT 222,114,4,4
INSERT INTO #t SELECT 222,115,5,2
INSERT INTO #t SELECT 222,116,6,4
INSERT INTO #t SELECT 222,117,7,2
INSERT INTO #t SELECT 222,118,8,4
INSERT INTO #t SELECT 222,119,9,4
INSERT INTO #t SELECT 222,120,10,2
INSERT INTO #t SELECT 222,121,11,2
INSERT INTO #t SELECT 222,124,12,4
INSERT INTO #t SELECT 222,126,13,4
INSERT INTO #t SELECT 222,128,14,4
INSERT INTO #t SELECT 223,126,13,4
INSERT INTO #t SELECT 223,128,14,4
INSERT INTO #t SELECT 223,129,15,2
INSERT INTO #t SELECT 223,130,16,4
INSERT INTO #t SELECT 224,111,17,4
INSERT INTO #t SELECT 224,112,18,4
INSERT INTO #t SELECT 223,160,33,4
INSERT INTO #t SELECT 223,161,34,4
INSERT INTO #t SELECT 223,162,35,4
INSERT INTO #t SELECT 223,163,40,4
;with HardcoreCTE AS
(
select t.*,
t.[Sequence] - ROW_NUMBER() OVER(PARTITION BY t.instructionId ORDER BY
t.InstructionDetailId) AS ItemCount
from #t t outer apply
( select top (1) t1.*
from #t t1
where t1.InstructionId = t.InstructionId and
t1.Sequence < t.Sequence
order by t1.Sequence desc
) t1 outer apply
( select top (1) t2.*
from #t t2
where t2.InstructionId = t.InstructionId and
t2.Sequence > t.Sequence
order by t2.Sequence
) t2
where t.status = 4 and (t.status = t1.status or t.status = t2.status)
)
,
HardCoreCTE2
AS
(
select *, Count(1) OVER(PARTITION BY ItemCount) AS ItemCount2 from
HardcoreCTE
)
select * from HardCoreCTE2
where ItemCount2 =2
So the above works brilliants to find results where there are specifically only 2 consecutive failures with these
results:
Now from the above results the only ones it finds are the records where there are 2 consecutive failures but whenever I convert the above to the actual test environment tables it doesn't seem to work.
Test Env Results: As you can see for the "InstructionId" of 2518380 it brought back one record and the for "InstructionId" 2614351. It's meant to bring back sets of 2 records.
Test Env Query: (Pretty much identical)
;with InitialDataCTE
AS
(
SELECT Instruction.InstructionID,InstructionDetail.InstructionDetailID,
InstructionDetail.InstructionDetailStatusID AS [Status],
InstructionDetail.Sequence
FROM Instruction INNER JOIN
InstructionDetail ON Instruction.InstructionID =
InstructionDetail.InstructionID
where InstructionDetailStatusID =4
and InstructionDetail.PaymentDateOriginal between '2015-01-05'
AND '2018-09-08'
),
HardCoreCTE
AS
(
select t.*,
t.Sequence - ROW_NUMBER() OVER(PARTITION BY t.instructionId ORDER BY
t.InstructionDetailId) AS ItemCount
from InitialDataCTE t outer apply
( select top (1) t1.*
from InitialDataCTE t1
where t1.InstructionId = t.InstructionID and
t1.Sequence < t.Sequence
order by t1.Sequence desc
) t1 outer apply
( select top (1) t2.*
from InitialDataCTE t2
where t2.InstructionId = t.InstructionId and
t2.Sequence > t.Sequence
order by t2.Sequence
) t2
where t.Status = 4 and (t.Status = t1.Status or t.Status = t2.Status)
)
,
HardCoreCTE2
AS
(
select *, Count(1) OVER(PARTITION BY ItemCount) AS ItemCount2 from
HardCoreCTE
)
select * from HardCoreCTE2
where ItemCount2 =2
order by InstructionID, Sequence
Really appreciate if someone can tell me where I am going wrong, I've been messing around with variations of the Count(*) but nothing successful yet. Thanx alot
I came to the next query:
with
a as (
select *,
row_number() over(partition by InstructionId order by Sequence)-
row_number() over(partition by InstructionId, [Status] order by Sequence) g
from #t
),
b as (
select *,
count(*) over(partition by InstructionId, [Status], g) c
from a
where [Status] = 4
)
select *
from b
where c > 2
order by 1, 3;
For your test data, I got the following result:
InstructionId InstructionDetailId Sequence Status g c
222 224 312 4 6 3
222 226 413 4 6 3
222 228 514 4 6 3
223 161 84 4 2 3
223 162 95 4 2 3
223 163 140 4 2 3
You can test this query here.

Unexpected result using CTE to perform a random join on two tables for all rows one-to-many

I am attempting to randomly join the rows of two tables (TableA and TableB) such that each row in TableA is joined to only one row in TableB and every row in TableB is joined to at least one row in TableA.
For example, a random join of TableA with 5 distinct rows and TableB with 3 distinct rows should result in something like this:
TableA TableB
1 3
2 1
3 1
4 2
5 1
However, sometimes not all the rows from TableB are included in the final result; so in the example above might have row 2 from TableB missing because in its place is either row 1 or 3 joined to row 4 on TableA. You can see this occur by executing the script a number of times and checking the result. It seems that it is necessary for some reason to use an interim table (#Q) to be able to ensure that a correct result is returned which has all rows from both TableA and TableB.
Can someone please explain why this is happening?
Also, can someone please advise on what would be a better way to get the desired result?
I understand that sometimes no result is returned due to a failure of some kind in the cross apply and ordering which i have yet to identify and goes to the point that I am sure there is a better way to perform this operation. I hope that makes sense. Thanks in advance!
declare #TableA table (
ID int
);
declare #TableB table (
ID int
);
declare #Q table (
RN int,
TableAID int,
TableBID int
);
with cte as (
select
1 as ID
union all
select
ID + 1
from cte
where ID < 5
)
insert #TableA (ID)
select ID from cte;
with cte as (
select
1 as ID
union all
select
ID + 1
from cte
where ID < 3
)
insert #TableB (ID)
select ID from cte;
select * from #TableA;
select * from #TableB;
with cte as (
select
row_number() over (partition by TableAID order by newid()) as RN,
TableAID,
TableBID
from (
select
a.ID as TableAID,
b.ID as TableBID
from #TableA as a
cross apply #TableB as b
) as M
)
select --All rows from TableB not always included
TableAID,
TableBID
from cte
where RN in (
select
top 1
iCTE.RN
from cte as iCTE
group by iCTE.RN
having count(distinct iCTE.TableBID) = (
select count(1) from #TableB
)
)
order by TableAID;
with cte as (
select
row_number() over (partition by TableAID order by newid()) as RN,
TableAID,
TableBID
from (
select
a.ID as TableAID,
b.ID as TableBID
from #TableA as a
cross apply #TableB as b
) as M
)
insert #Q
select
RN,
TableAID,
TableBID
from cte;
select * from #Q;
select --All rows from both TableA and TableB included
TableAID,
TableBID
from #Q
where RN in (
select
top 1
iQ.RN
from #Q as iQ
group by iQ.RN
having count(distinct iQ.TableBID) = (
select count(1) from #TableB
)
)
order by TableAID;
See if this gives you what you're looking for...
DECLARE
#CountA INT = (SELECT COUNT(*) FROM #TableA ta),
#CountB INT = (SELECT COUNT(*) FROM #TableB tb),
#MinCount INT;
SELECT #MinCount = CASE WHEN #CountA < #CountB THEN #CountA ELSE #CountB END;
WITH
cte_A1 AS (
SELECT
*,
rn = ROW_NUMBER() OVER (ORDER BY NEWID())
FROM
#TableA ta
),
cte_B1 AS (
SELECT
*,
rn = ROW_NUMBER() OVER (ORDER BY NEWID())
FROM
#TableB tb
),
cte_A2 AS (
SELECT
a1.ID,
rn = CASE WHEN a1.rn > #MinCount THEN a1.rn - #MinCount ELSE a1.rn end
FROM
cte_A1 a1
),
cte_B2 AS (
SELECT
b1.ID,
rn = CASE WHEN b1.rn > #MinCount THEN b1.rn - #MinCount ELSE b1.rn end
FROM
cte_B1 b1
)
SELECT
A = a.ID,
B = b.ID
FROM
cte_A2 a
JOIN cte_B2 b
ON a.rn = b.rn;

SQL Server Joining Between Two Tables Based on Closest Value

I have two sets of data, as shown below.
Table 1:
enter code here
ID Value_1
1 233.67
2 83.28
3 84.49
4 1234.83
Table 2:
NewID Value_3 Value_4
5 NULL 83
6 NULL 85
7 NULL 235
I want to join the two tables in such a way that the resulting data set would look like below.
ID NewID Value_1 Value_2
1 7 233.67 235
2 5 83.28 83
3 6 84.49 85
4 NULL 1234.83 NULL
I know that using the ROUND command would cause future problems. Do any of you know how I could create the above resulting set?
Something like this:
DECLARE #Table1 TABLE
(
Id int,
Value1 float
)
INSERT INTO #Table1
VALUES
(1, 233.67),
(2, 83.28),
(3, 84.49),
(4, 1234.83)
DECLARE #Table2 TABLE
(
NewId int,
Value2 float
)
INSERT INTO #Table2
VALUES
(5, 83),
(6, 85),
(7, 235)
SELECT DISTINCT
t1.Id,
FIRST_VALUE(t2.NewId) OVER (PARTITION BY t1.Id ORDER BY ABS(t1.Value1 - t2.Value2) ASC) AS NewId,
t1.Value1,
FIRST_VALUE(t2.Value2) OVER (PARTITION BY t1.Id ORDER BY ABS(t1.Value1 - t2.Value2) ASC) AS Value2
FROM #Table1 t1
CROSS JOIN #Table2 t2
ORDER BY t1.Id
But you will get a result for ID=4 too.
This approach avoids a cross join, which requires every combination to be tested. It also works with SQL Server 2005 and up. It works by calculating a lower and upper bound between the midpoints of each record in Table2 and then joining on Table1 where Value_1 is between the midpoints. If Value_1 lands right on the boundary this code will round up (choose the higher of Value_4 to match).
--Load Table1
select 1 ID, convert(float,233.67) Value_1 into #Table1
insert into #Table1 select 2, 83.28
insert into #Table1 select 3, 84.49
insert into #Table1 select 4, 1234.83
--Load Table2
select 5 NewID, null Value_3, convert(float,83) Value_4 into #Table2
insert into #Table2 select 6, NULL, 85
insert into #Table2 select 7, NULL, 235
;with cte_Table2 as
(
select *, ROW_NUMBER() over (order by Value_4) OrderNum
from #Table2
)
Select #Table1.ID,
NewTable2.NewID,
#Table1.Value_1,
NewTable2.Value_4 Value_2
from #Table1
full join
(
select Table2.NewID,
Table2.Value_3,
Table2.Value_4,
Table2Prev.Value_4 + (Table2.Value_4 - Table2Prev.Value_4) / 2.0 LowerBound,
Table2.Value_4 + (Table2Next.Value_4 - Table2.Value_4) / 2.0 UpperBound
from cte_Table2 Table2
left join cte_Table2 Table2Prev
on Table2.OrderNum = Table2Prev.OrderNum + 1
left join cte_Table2 Table2Next
on Table2.OrderNum = Table2Next.OrderNum - 1
) NewTable2
on (#Table1.Value_1 < UpperBound or UpperBound is null)
and (#Table1.Value_1 >= LowerBound or LowerBound is null)
order by 1
I noticed that you did not show a match for ID of 4 in your expected output. If you need some kind of range to exclude matches then you would have to add that restriction to the ON conditions of the join. For example you could exclude values that are outside a threshold of 10 by making sure you use a FULL JOIN and add this to the ON conditions:
and abs(#Table1.Value_1-NewTable2.Value_4) < 10.0
It occurs to me though that maybe what you are really trying to do is a type of join where not only is the value in Table1 matched with it's closest value in Table2 but the value in Table2 is also the closest value in Table1. In this case, you would have to build a sub-query for Table1 with the boundary conditions and then check for it's closest match as well. Like this:
;with cte_Table1 as
(
select *, ROW_NUMBER() over (order by Value_1) OrderNum
from #Table1
),
cte_Table2 as
(
select *, ROW_NUMBER() over (order by Value_4) OrderNum
from #Table2
)
Select NewTable1.ID,
NewTable2.NewID,
NewTable1.Value_1,
NewTable2.Value_4 Value_2
from
(
select Table1.ID,
Table1.Value_1,
Table1Prev.Value_1 + (Table1.Value_1 - Table1Prev.Value_1) / 2.0 LowerBound,
Table1.Value_1 + (Table1Next.Value_1 - Table1.Value_1) / 2.0 UpperBound
from cte_Table1 Table1
left join cte_Table1 Table1Prev
on Table1.OrderNum = Table1Prev.OrderNum + 1
left join cte_Table1 Table1Next
on Table1.OrderNum = Table1Next.OrderNum - 1
) NewTable1
full join
(
select Table2.NewID,
Table2.Value_3,
Table2.Value_4,
Table2Prev.Value_4 + (Table2.Value_4 - Table2Prev.Value_4) / 2.0 LowerBound,
Table2.Value_4 + (Table2Next.Value_4 - Table2.Value_4) / 2.0 UpperBound
from cte_Table2 Table2
left join cte_Table2 Table2Prev
on Table2.OrderNum = Table2Prev.OrderNum + 1
left join cte_Table2 Table2Next
on Table2.OrderNum = Table2Next.OrderNum - 1
) NewTable2
on (NewTable1.Value_1 < NewTable2.UpperBound or NewTable2.UpperBound is null)
and (NewTable1.Value_1 >= NewTable2.LowerBound or NewTable2.LowerBound is null)
and (NewTable2.Value_4 < NewTable1.UpperBound or NewTable1.UpperBound is null)
and (NewTable2.Value_4 >= NewTable1.LowerBound or NewTable1.LowerBound is null)
order by 1
Now the records in the tables will only match if the values are the closest match both ways. This will ensure that each record in Table1 will be matched to at most 1 value in Table2. Because it's a full join you can get null values on either side... depending on which table is smaller.
One more thing to mention... this code might not handle duplicate values the way you need. If you have more than one of the same value in either Value_1 or Value_4, it will find a match to one of them but not both. If you want that... then you would have to change your common table expressions to:
;with cte_Table1 as
(
select *, ROW_NUMBER() over (order by Value_1) OrderNum
from (select distinct Value_1 from #Table1) tbl1
),
cte_Table2 as
(
select *, ROW_NUMBER() over (order by Value_4) OrderNum
from (select distinct Value_4 from #Table2) tbl2
)
Then update your sub-queries to only output the values with the boundaries. This would give you best matches with between the unique values. Then you could join to Table1 and Table2 ON Table1.Value_1 = NewTable1.Value1 and Table2.Value_4 = NewTable2.Value_4 to get the rest of the fields.
Certainly some optimizations can be made if you have very large tables... like breaking out some of these sub-queries into indexed temporary tables.

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

select records After top 1000 rows

I want to select records from 1000 to 2000 rows and so on in batch of 1000.
I have written query to select top 1000 records but how can i select from 1000 to 2000.
can you help me with a query that can select those records.
SELECT TOP 1000 *
FROM tblProductInformation p1 INNER JOIN tblProduct1 p
ON p.productname = p1.productname
I think you need to order on specific a column, for example order on the primary key.
SELECT *
FROM
(
SELECT tbl.*, p.*, ROW_NUMBER() OVER (ORDER BY ProductID_PRIMARYKEY) rownum
FROM tblProductInformation as tbl INNER JOIN tblProduct1 p
ON p.productname = p1.productname
) seq
WHERE seq.rownum BETWEEN 1000 AND 2000
WITH cte AS(
SELECT ROW_NUMBER()OVER(Order By p1.productname ASC, p1.ID ASC) As RowNum
,p1 .*
from tblProductInformation p1
inner join tblProduct1 p on p.productname = p1.productname
)
SELECT * FROM cte
WHERE RowNum BETWEEN #FromRowNum AND #ToRowNum
ROW_NUMBER: http://msdn.microsoft.com/en-us/library/ms186734.aspx
Paging on SQL-Server: http://www.mssqltips.com/sqlservertip/1175/page-through-sql-server-results-with-the-rownumber-function/
WITH Results AS (
select TOP 1000 f.*, ROW_NUMBER() OVER (ORDER BY f.[type]) as RowNumber
from tblProductInformation f
) select *
from Results
where RowNumber between 1001 and 2000
tutorial
Answer Late .. but could be helpful for some one coming here ... simple one
Another simple approach ...
You can create a similar table "tblProductInformation_tmp" OR #tblProductInformation_tmp - with an extra column "UniqueID" and make that auto-increment IDENTITY column.
then just insert the same data to table :
insert * into tblProductInformation_tmp
select * from tblProductInformation
Now its simple ryt :
select * from tblProductInformation_tmp where UniqueID < 1001
select * from tblProductInformation_tmp where UniqueID between 1001 and 2001
:) Dont forget to delete : tblProductInformation_tmp
Rigin

Resources