I want to join a table on 4 conditions, of which 2 are very straightforward and 2 other conditions which are more difficult.
The first two:
PMCCONTRACTSTATUS.ContractID = CUSTAMOUNTREPORTTABLE.ContractID
PMCCONTRACTSTATUS.DATAAREAID = CUSTAMOUNTREPORTTABLE.DATAAREAID
The second two:
Only if the FROMDATE from Table PMCCONTRACTSTATUS is lower then the PERIODSTART in Table CUSTAMOUNTREPORTTABLE
AND only if that is the case THEN Take the highest RowNumber. EDIT: Because I want to JOIN the [STATUS] that is the CLOSEST to the PERIODSTART.
EDIT: I Made a sample dataset which only includes the necessary parts to solve the problem.
CREATE TABLE PMCCONTRACTSTATUSLOG2 (
ContractID nvarchar(20)
,[Status] int
,FromDate date
,RowNumber int
);
CREATE TABLE CUSTAMOUNTREPORTTABLE2 (
ContractID nvarchar(20)
,PERIODSTART date
);
INSERT INTO PMCCONTRACTSTATUSLOG2
(ContractID, [Status], FromDate, RowNumber)
VALUES
('HC1','1','01-01-2019','1'),
('HC1','2','01-02-2019','2'),
('HC1','1','01-04-2019','3'),
('HC2','1','01-04-2019','1'),
('HC2','2','01-05-2019','2'),
('HC3','4','01-01-2019','1'),
('HC3','2','01-02-2019','2'),
('HC3','1','01-07-2019','3'),
('HC3','2','01-09-2019','4'),
('HC4','2','01-08-2019','1'),
('HC4','3','01-07-2019','2'),
('HC5','1','01-02-2019','1');
INSERT INTO CUSTAMOUNTREPORTTABLE2
(ContractID, PERIODSTART)
VALUES
('HC1','01-01-2019'),
('HC2','01-01-2019'),
('HC3','01-01-2019'),
('HC5','01-01-2019'),
('HC1','01-02-2019'),
('HC3','01-02-2019'),
('HC5','01-02-2019'),
('HC1','01-03-2019'),
('HC3','01-03-2019'),
('HC5','01-03-2019'),
('HC1','01-04-2019'),
('HC2','01-04-2019'),
('HC3','01-04-2019'),
('HC5','01-04-2019'),
('HC1','01-05-2019'),
('HC2','01-05-2019'),
('HC3','01-05-2019'),
('HC5','01-05-2019');
SELECT * FROM PMCCONTRACTSTATUSLOG2
SELECT * FROM CUSTAMOUNTREPORTTABLE2
I try with the following query to join the PMCCONTRACTSTATUS Table, I know the logic behind the join, but I fail to write a JOIN that combines a CASE WHEN + SELECT statement.
;WITH PMCCONTRACTSTATUS AS
(
SELECT
CONTRACTID
,[STATUS]
,FROMDATE
,DATAAREAID
,ROW_NUMBER() OVER (PARTITION BY CONTRACTID ORDER BY FROMDATE ASC) RN
FROM PMCCONTRACTSTATUSLOG
WHERE [STATUS] <> 10 OR [STATUS] <> 5
)
SELECT
CART.CONTRACTID
,PMCCONTRACTSTATUS.CONTRACTID
,CART.ACCOUNTNUM
,CART.AMOUNTMSTTOTAL
,CART.PERIODSTART
,PMCCONTRACTSTATUS.FROMDATE
,CART.PERIODEND
,CART.NAME
,CART.PMCCONTRACTSTATUSWEIGHTED
,PMCCONTRACTSTATUS.[STATUS]
FROM CUSTAMOUNTREPORTTABLE CART
LEFT JOIN PMCCONTRACTSTATUS
ON PMCCONTRACTSTATUS.CONTRACTID = CART.CONTRACTID
AND PMCCONTRACTSTATUS.DATAAREAID = CART.DATAAREAID
/*AND CASE WHEN PMCCONTRACTSTATUS.FROMDATE <= CART.PERIODSTART
THEN (SELECT MAX(PMCCONTRACTSTATUSLOG.RN) FROM PMCCONTRACTSTATUSLOG)*/
Any suggestions?
This answer is based from my understanding, maybe some parts are missing :
First I try to join with your 3 first conditions in a CTE. And then I create a ROW_NUMBER() based on the DATEDIFF between your 2 dates.
Tell me if it helps :
;WITH
CTE AS (
SELECT
CART.CONTRACTID
,CART.ACCOUNTNUM
,CART.AMOUNTMSTTOTAL
,CART.PERIODSTART
,PMCCONTRACTSTATUSLOG.FROMDATE
,CART.PERIODEND
,CART.NAME
,CART.PMCCONTRACTSTATUSWEIGHTED
,PMCCONTRACTSTATUSLOG.[STATUS]
,ROW_NUMBER() OVER (PARTITION BY CART.CONTRACTID,CART.DATAAREAID ORDER BY DATEDIFF(second,FROMDATE,PERIODSTART) ASC) RN
FROM CUSTAMOUNTREPORTTABLE CART
LEFT JOIN PMCCONTRACTSTATUSLOG
ON PMCCONTRACTSTATUSLOG.CONTRACTID = CART.CONTRACTID
AND PMCCONTRACTSTATUSLOG.DATAAREAID = CART.DATAAREAID
AND PMCCONTRACTSTATUSLOG.FROMDATE <= CART.PERIODSTART
WHERE [STATUS] NOT IN (5,10)
)
SELECT
CONTRACTID
,ACCOUNTNUM
,AMOUNTMSTTOTAL
,PERIODSTART
,FROMDATE
,PERIODEND
,NAME
,PMCCONTRACTSTATUSWEIGHTED
,[STATUS]
FROM CTE
WHERE RN = 1
I believe you should use OUTER APPLY instead of LEFT JOIN
;WITH PMCCONTRACTSTATUS AS
(
SELECT
CONTRACTID
,[STATUS]
,FROMDATE
,DATAAREAID
,ROW_NUMBER() OVER (PARTITION BY CONTRACTID ORDER BY FROMDATE ASC) RN
FROM PMCCONTRACTSTATUSLOG
WHERE [STATUS] <> 10 OR [STATUS] <> 5
)
SELECT
CART.CONTRACTID
,PMCCONTRACTSTATUS.CONTRACTID
,CART.ACCOUNTNUM
,CART.AMOUNTMSTTOTAL
,CART.PERIODSTART
,MAX_PMCCONTRACTSTATUS.FROMDATE
,CART.PERIODEND
,CART.NAME
,CART.PMCCONTRACTSTATUSWEIGHTED
,MAX_PMCCONTRACTSTATUS.[STATUS]
FROM CUSTAMOUNTREPORTTABLE CART
OUTER APPLY (select top 1 *
from PMCCONTRACTSTATUS
where PMCCONTRACTSTATUS.CONTRACTID = CART.CONTRACTID
AND PMCCONTRACTSTATUS.DATAAREAID = CART.DATAAREAID
AND PMCCONTRACTSTATUS.FROMDATE <= CART.PERIODSTART
ORDER BY PMCCONTRACTSTATUSLOG.RN DESC) as MAX_PMCCONTRACTSTATUS
The table1 has huge rows and field1 is text, so I create a fulltext-index of field1.
I run the sql below, it's very slowly, and the CPU to 100% all the way.
select * from (
select *, ROW_NUMBER() OVER(Order by [createtime] DESC) AS RowId
from table1
where CONTAINS(field1, 'sometext')
) AS t1
where t1.RowId between 1 and 10
I remove RowId query, it becomes fast, less than 1s.
select * from (
select *, ROW_NUMBER() OVER(Order by [createtime] DESC) AS RowId
from table1
where CONTAINS(field1, 'sometext')
) AS t1
Then I think it's about of SQLServer optimization, I try to add zero to RowId query field.
It goes fast! But why?
select * from (
select *, ROW_NUMBER() OVER(Order by [createtime] DESC) AS RowId
from table1
where CONTAINS(field1, 'sometext')
) AS t1
where t1.RowId + 0 between 1 and 10
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;
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
I want try update a table using random values from the same table, but the original table donĀ“t have a identity to follow or any other number column...
WITH cteTable1 AS (
SELECT
ROW_NUMBER() OVER (ORDER BY NEWID()) AS n,
ENDE_NO_Address
FROM TableX
)
UPDATE TableX SET ENDE_NO_Address = (
SELECT ENDE_NO_Address
FROM cteTable1
WHERE cteTable1.n = This is the problem...
tnks for the help
Guessing...
UPDATE TableX
SET ENDE_NO_Address = (
SELECT TOP 1 ENDE_NO_Address FROM TableX ORDER BY NEWID()
)
declare #T table(Col1 varchar(10))
insert into #T values (1),(2),(3),(4),(5)
;with cte as
(
select *,
row_number() over(order by newid()) as rn1,
row_number() over(order by Col1) as rn2
from #T
)
update C1 set
Col1 = C2.Col1
from cte as C1
inner join cte as C2
on C1.rn1 = C2.rn2
Edit:
WITH cte AS (
SELECT
ROW_NUMBER() OVER (ORDER BY NEWID()) AS n1,
ROW_NUMBER() OVER (ORDER BY (select 1)) AS n2,
ENDE_NO_Address
FROM TableX
)
update C1 set
ENDE_NO_Address = C2.ENDE_NO_Address
from cte as C1
inner join cte as C2
on C1.n1 = C2.n2