I will made a simple exemple to understand better what I'm trying to do:
I have Selection 1 witch takes data from 4 tables with severals inner join. The results is like image shown bellow:
I have Selection 2 witch takes data from another 4 tables.
The only difference between this 2 results of the selections is the column 4.
The results is like image shown bellow:
The results I want is like this:
If I make UNION ALL he put the values underneath (the result is with 20 rows), and I don't need like that.
If I Make Join between them I have 10x10=100 rows.
EXEMPLE LINK: SQLFiddle
Get data from both selection with inner joins and display only required columns from both selections
;WITH CTE1
AS
(
SELECT * FROM SELECTION1
)
,CTE2
AS
(
SELECT * FROM SELECTION2
)
SELECT
CTE1.UNAME,
CTE1.PRE_NAME,
CTE1.TIME,
CTE1.FIRST_VALUE,
CTE2.FINAL_VALUE
FROM CTE1
INNER JOIN CTE2
ON CTE1.UNAME=CTE2.UNAME
AND CTE1.PRE_NAME=CTE2.PRE_NAME
AND CTE1.TIME=CTE2.TIME
UPDATE
FIDDLE
I have tried to get something unique from both tables so used ROW_NUMBER(). This might help. Joins with duplicate values in both tables will make it 10x10 rows only which you don't want.
WITH CTE1
AS
(
SELECT ROW_NUMBER() OVER (ORDER BY U_NAME) AS NO, * FROM SELECTION1
)
,CTE2
AS
(
SELECT ROW_NUMBER() OVER (ORDER BY U_NAME) AS NO,* FROM SELECTION2
)
SELECT
CTE1.U_NAME,
CTE1.PRE_NAME,
CTE1.TIME,
CTE1.FIRST_VALUE,
CTE2.FINAL_VALUE
FROM CTE1
INNER JOIN CTE2
ON CTE1.NO=CTE2.NO
UPDATE 2
WITH CTE1
AS
(
SELECT ROW_NUMBER() OVER (ORDER BY UD_NAME) AS NO, * FROM
(
SELECT R0507UNIT_.R0507NAME_ AS UD_NAME,
R0101MAPAR.R0101NAME_ AS PRE_NAME,
TO_CHAR(D0903GSCHH.D0903TFROM + INTERVAL '2' HOUR, 'DD.MM.YYYY HH24:MI:SS') AS TIME_FROM,
D0904GSCHI.D0904POWER AS FINAL_POWER
FROM D0904GSCHI
INNER JOIN D0903GSCHH
ON
D0904GSCHI.D0903TFROM = D0903GSCHH.D0903TFROM
AND D0904GSCHI.D0903ID___ = D0903GSCHH.D0903ID___
INNER JOIN R0101MAPAR
ON
D0903GSCHH.R0101ID___ = R0101MAPAR.R0101ID___
INNER JOIN R0507UNIT_
ON
D0903GSCHH.R0507ID___=R0507UNIT_.R0507ID___
WHERE D0903GSCHH.D0903TFROM >= TO_DATE('07.02.2017 20:00','DD.MM.YYYY HH24:MI:SS')
AND D0903GSCHH.D0903TFROM < TO_DATE('08.02.2017 20:00','DD.MM.YYYY HH24:MI:SS')
--AND R0507UNIT_.R0507NAME_ = 'BUCV3'
) AS A --THIS IS AN ALIAS
)
SELECT A.U_NAME,
A.PRE_NAME,
A.TIME,
A.FIRST_VALUE,
B.FINAL_VALUE
FROM Selection1 AS A
INNER JOIN Selection2 AS B
ON A.U_NAME = B.U_NAME
AND A.PRE_NAME = B.PRE_NAME
AND A.TIME = B.TIME
You need to join the two queries together using an INNER JOIN:
SELECT s1.U_NAME
,s1.PRE_NAME
,s1.TIME
,s1.FIRST_VALUE
,s2.FINAL_VALUE
FROM (
-- First query
SELECT U_NAME, PRE_NAME, TIME, FIRST_VALUE
FROM Selection1
) s1
INNER JOIN (
-- Second query
SELECT U_NAME, PRE_NAME, TIME, FINAL_VALUE
FROM Selection1
) s2
ON s1.U_NAME = s2.U_NAME
AND s1.PRE_NAME = s2.PRE_NAME
AND s1.TIME = s2.TIME
;
If I consider the two inputs as tables, you can achieve the desired results with another join between the these tables (But i will not suggest it due to performance issues).
SELECT
TBL1.U_NAME,TBL1.PRE_NAME,TBL1.TIME,TBL1.FIRST_VALUE,TBL2.FINAL_VALUE FROM
FROM FIRSTTABLE TBL1 INNER JOIN SECONDTABLE TBL2 ON TBL1.U_NAME=TBL2.U_NAME
AND TBL1.PRE_NAME=TBL2.PRE_NAME AND TBL1.TIME=TBL2.TIME
I see your already have some inner joins to get data in FirstTable and SecondTable. If both of these queries are using common tables to bring data, you can do it in a single query also. If I am understanding your problem correctly, Union is not required for the kind of resultset you are looking for.
If you can provide the complete query it would give more context and can provide a better solution.
BEGIN TRAN
CREATE TABLE #temp (U_Name Nvarchar(20),PRE_Name Nvarchar(20),Time Datetime,firstValue int)
CREATE TABLE #temp1 (U_Name Nvarchar(20),PRE_Name Nvarchar(20),Time Datetime,firstValue int)
INSERT INTO #temp
Select 'GV','NMOP','10.02.2017', 90 UNION ALL
Select 'GV','NMOP','10.02.2017', 100 UNION ALL
Select 'GV','NMOP','10.02.2017', 120 UNION ALL
Select 'GV','NMOP','10.02.2017', 300 UNION ALL
Select 'GV','NMOP','10.02.2017', 200 UNION ALL
Select 'GV','NMOP','10.02.2017', 100 UNION ALL
Select 'GV','NMOP','10.02.2017', 50 UNION ALL
Select 'GV','NMOP','10.02.2017', 60 UNION ALL
Select 'GV','NMOP','10.02.2017', 70 UNION ALL
Select 'GV','NMOP','10.02.2017', 10
INsert into #temp1
Select 'GV','NMOP','10.02.2017', 60 UNION ALL
Select 'GV','NMOP','10.02.2017', 52 UNION ALL
Select 'GV','NMOP','10.02.2017', 10 UNION ALL
Select 'GV','NMOP','10.02.2017', 300 UNION ALL
Select 'GV','NMOP','10.02.2017', 33 UNION ALL
Select 'GV','NMOP','10.02.2017', 100 UNION ALL
Select 'GV','NMOP','10.02.2017', 50 UNION ALL
Select 'GV','NMOP','10.02.2017', 56 UNION ALL
Select 'GV','NMOP','10.02.2017', 99 UNION ALL
Select 'GV','NMOP','10.02.2017', 10
SELECT ROW_NUMBER() OVER (ORDER BY U_NAME) AS Rowno,a.U_Name, a.PRE_Name,a.Time,a.firstValue into #t from #temp a
SELECT ROW_NUMBER() OVER (ORDER BY U_NAME) AS Rowno, b.U_Name, b.PRE_Name,b.Time,b.firstValue as finalValue INTO #TT from #temp1 b
SELECT a.U_Name,a.PRE_Name,a.Time,a.firstValue, b.finalValue
FROM #t a
INNER JOIN #TT b ON a.Rowno=b.Rowno AND a.U_Name=b.U_Name AND a.PRE_Name=b.PRE_Name AND a.time=b.Time
ROLLBACK TRAN
Related
Merge three tables in a Select query by rule 3, 2, 1 records from each table as follows:
TableA: ID, FieldA, FieldB, FieldC,....
TableB: ID, FieldA, FieldB, FieldC,....
TableC: ID, FieldA, FieldB, FieldC,....
ID : auto number in each table
FieldA will be unique in all three tables.
I am looking for a Select query to merge three tables as follows:
TOP three records from TableA sorted by ID
TOP two records from TableB sorted by ID
TOP 1 record from TableC sorted by ID
Repeat this until select all records from all three tables.
If some table has fewer records or does not meet the criteria, ignore that and continue with others.
My attempt:
I did it totally through programming way, like cursors and If conditions inside a SQL Server stored procedure.
It makes delay.
This requires a formula that takes row numbers from each table and transforms it into a series of integers that skips the desired values.
In the query below, I am adding some CTE for the sake of shortening the formula. The real magic is in the UNION. Also, I am adding an additional field for your control. Feel free to get rid of it.
WITH A_Aux as (
SELECT 'A' As FromTable, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum, TableA.*
FROM TableA
), B_Aux AS (
SELECT 'B' As FromTable, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum, TableB.*
FROM TableB
), C_Aux AS (
SELECT 'C' As FromTable, ROW_NUMBER() OVER (Order BY ID) AS RowNum, TableC.*
FROM TableC
)
SELECT *
FROM (
SELECT RowNum+3*FLOOR((RowNum-1)/3) As ColumnForOrder, A_Aux.* FROM A_Aux
UNION ALL
SELECT 3+RowNum+4*FLOOR((RowNum-1)/2), B_Aux.* FROM B_Aux
UNION ALL
SELECT 6*RowNum, C_Aux.* FROM C_Aux
) T
ORDER BY ColumnForOrder
PS: note the pattern Offset + RowNum + (6-N) * Floor((RowNum-1)/N) to group N records together (it of course simplifies a lot for TableC).
PPS: I don't have a SQL server at hand to test it. Let me know if there is a syntax error.
You may try this..
GO
select * into #temp1 from (select * from table1) as t1
select * into #temp2 from (select * from table2) as t2
select * into #temp3 from (select * from table3) as t3
select * into #final from (select col1, col2, col3 from #temp1 where 1=0) as tb
declare #i int
set #i=1
while( (select COUNT(*) from #temp1)>#i)
Begin
;with ct1 as (
select ROW_NUMBER() over (order by id) as Slno, * from #temp1
),ct2 as (
select ROW_NUMBER() over (order by id) as Slno, * from #temp2
),ct3 as (
select ROW_NUMBER() over (order by id) as Slno, * from #temp3
),cfinal as (
select top 3 * from #temp1
union all
select top 2 * from #temp2
union all
select top 1 * from #temp3
)
insert into #final ( col1 , col2, col3 )
select col1, col2, col3 from cfinal
delete from #temp1 where id in (select top 3 ID from #temp1)
delete from #temp2 where id in (select top 2 ID from #temp2)
delete from #temp3 where id in (select top 1 ID from #temp3)
set #i = #i+1
End
Select * from #final
Drop table #temp1
Drop table #temp2
Drop table #temp3
GO
First create temp table for all 3 tables with each insert delete the inserted record and this will result you the desired result, if nothing is missing from my side.
Please see to this if this works.
There is not a lot of information to go with here, but I assume you can use UNION to combine multiple statements.
SELECT * TableA ORDER BY ID DESC OFFSET 3 ROWS
UNION
SELECT * TableB ORDER BY ID DESC OFFSET 2 ROWS
UNION
SELECT * TableC ORDER BY ID DESC OFFSET 1 ROWS
Execute and see if this works.
/AF
From my understanding, I create three temp tables as ta, tb, tc.
select * into #ta from (
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
) a
select * into #tb from (
select 'B' b
union all
select 'B'
union all
select 'B'
union all
select 'B'
union all
select 'B'
) b
select * into #tc from (
select 'C' c
union all
select 'C'
union all
select 'C'
union all
select 'C'
union all
select 'C'
) c
If tables match you tables, then the output looks like A,A,A,B,B,C,A,A,A,B,B,C,A,B,C,C,C
T-SQL
declare #TAC int = (select count (*) from #ta) -- Table A Count = 7
declare #TBC int = (select count (*) from #tb) -- Table B Count = 5
declare #TAR int = #TAC % 3 -- Table A Reminder = 1
declare #TBR int = #TBC % 2 -- Table B Reminder = 1
declare #TAQ int = (#TAC - #TAR) / 3 -- Table A Quotient = (7 - 1) / 3 = 2, is will passed on NTILE
-- So we gonna split as two group (111), (222)
declare #TBQ int = (#TBC - #TBR) / 2 -- Table B Quotient = (5 - 1) / 2 = 2, is will passed on NTILE
-- So we gonna split as two group (11), (22)
select * from (
select *, NTILE (#TAQ) over ( order by a) FirstOrder, 1 SecondOrder from (
select top (#TAC - #TAR) * from #ta order by a
) ta -- 6 rows are obtained out of 7.
union all
select *, #TAQ + 1, 1 from (
select top (#TAR) * from #ta order by a desc
) ta -- Remaining one row is obtained. Order by desc is must
-- Here FirstOrder is next value of previous value.
union all
select *, NTILE (#TBQ) over ( order by b), 2 from (
select top (#TBC - #TBR) * from #tb order by b
) tb
union all
select *, #TBQ + 1, 2 from (
select top (#TBR) * from #tb order by b desc
) tb
union all
select *, ROW_NUMBER () over (order by c), 3 from #tc
) abc order by FirstOrder, SecondOrder
Let me explain the T-SQL:
Before that, FYR: NTILE and Row Number
Get the count.
Find the Quotient which will pass to NTILE function.
Order by the NTILE value and static.
Note:
I am using SQL Server 2017.
If T-SQL works fine, then you need to change the column in order by <yourcolumn>.
I'm currently writing code in SQL to add the column in red to the following table:
The logic is the following:
For every row:
if flag for this row =1 then use date of this row
if flag for this row =0 then find the latest row (based on date) on which flag was = 1 for the same party and return the date of that row. If no such row exists, return null
I've found a way to do this by joining the table to itself but I would like to avoid doing that as the size of the table is pretty massive.
What I have
select b.*, a.date,
from table a left join table b on a.party=b.party
where a.flag =1
Someone told me I could use the lag function, the partition over function and a case when to return the value I'm after but I haven't been able to figure it out.
Can someone help? Thank you so much!
try this
DECLARE #tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
INSERT INTO #tab1
SELECT 'A','7-24-2018',1 Union ALL
SELECT 'A','7-28-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'B','7-13-2018',1 Union ALL
SELECT 'B','7-17-2018',0 Union ALL
SELECT 'B','7-18-2018',0 Union ALL
SELECT 'C','7-8-2018',1 Union ALL
SELECT 'C','7-13-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-20-2018',0
select t.*,
max(case when flag = 1 then date end) over (partition by PARTY order by date) as [Last Flag On Date]
from #tab1 t
try this :->
select b.*, a.date, from table a left join table b on a.party=b.party where a.flag = CASE WHEN a.flag = 1 THEN a.date WHEN a.flag = 0 THEN ( SELECT date FROM ( SELECT TOP 1 row_number() OVER ( ORDER BY a.date DESC ) rs , a.date FROM a WHERE a.flag = 1 GROUP BY a.date) s ) END
use CROSS APPLY() to obtain the latest row with flag 1
SELECT *
FROM yourtable t
CROSS APPLY
(
SELECT TOP 1 x.Date as [Last flag on date]
FROM yourtable x
WHERE x.Party = t.Party
AND x.Flag = 1
ORDER BY x.Date desc
) d
Yes it can be done by joining table, if written properly.
#Sahi query is also good and simple.
Since you were asking for Dynamic LAG()
This query may or may not be very performant,but it certainly worth learning.
Test this with various sample data and tell me for which scenario it do not work.
So that I correct my script accordingly.
DECLARE #tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
INSERT INTO #tab1
SELECT 'A','7-24-2018',1 Union ALL
SELECT 'A','7-28-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'B','7-13-2018',1 Union ALL
SELECT 'B','7-17-2018',0 Union ALL
SELECT 'B','7-18-2018',0 Union ALL
SELECT 'C','7-8-2018',1 Union ALL
SELECT 'C','7-13-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-20-2018',0;
WITH cte
AS (SELECT *,
Row_number()
OVER (
partition BY party
ORDER BY flag DESC, [date] DESC ) rn
FROM #tab1)
SELECT *,
CASE
WHEN flag = 1 THEN [date]
ELSE Lag([date], (SELECT TOP 1 a.rn - a1.rn
FROM cte a1
WHERE a1.party = a.party))
OVER (
ORDER BY party )
END
FROM cte a
I have been given a script to clean up which uses approx 85 temp tables, I have been advised to use Common Table Expressions.
I have 3 CTE's, the first is the result of 7 tables pulled together using Union all. Followed by 2 more CTE's. The script runs up to:
select * from CTE_1
Union all
select * from CTE_2
Union all
select * from CTE_3
I then want to put all these results into a reusable table so I can then add some joins with various case statement logic. How can I put these into a temp table so that I can reference it later.
I'm looking to reduce the amount of temp tables so rather than put each CTE into a temp table I would ideally put multiple CTE's into one temp table. I currently have:
; with [CTE One] as (
select 1 as col
),
[CTE Two] as (
select 2 as col
),
[CTE Three] as (
select 3 as col
)
select * from CTE_1
Union all
select * from CTE_2
Union all
select * from CTE_3
Alternatively..
IF ( OBJECT_ID('tempdb..#temptable') IS NOT NULL )
BEGIN
DROP TABLE #temptable
END
CREATE TABLE #temptable
(
val int
)
;
WITH [CTE One]
AS ( SELECT 1 AS col
),
[CTE Two]
AS ( SELECT 2 AS col
),
[CTE Three]
AS ( SELECT 3 AS col
)
INSERT INTO #temptable (val)
SELECT *
FROM ( SELECT *
FROM CTE_1
UNION ALL
SELECT *
FROM CTE_2
UNION ALL
SELECT *
FROM CTE_3
) T
Can't you just use into?
select *
into #temptable
from CTE_1
Union all
select * from CTE_2
Union all
select * from CTE_3;
I might also be inclined to use a table variable, if the code is structured appropriately.
MY question is simple, How do you avoid the automatic sorting which the UNION ALL query does?
This is my query
SELECT * INTO #TEMP1 FROM Final
SELECT * INTO #TEMP2 FROM #TEMP1 WHERE MomentId = #MomentId
SELECT * INTO #TEMP3 FROM #TEMP1 WHERE RowNum BETWEEN #StartRow AND #EndRow
SELECT * INTO #TEMP4 FROM (SELECT *FROM #TEMP3 UNION ALL SELECT *FROM #TEMP2) as tmp
SELECT DISTINCT * FROM #TEMP4
I'm using SQL Server 2008. I need the Union ALL to perform like a simple Concatenate, which it isn't! Appreciate your help in this.
I think you're mistaken on which operation is actually causing the sort. Check the code below, UNION ALL will not cause a sort. You may be looking at the DISTINCT operation, which uses a sort (it sorts all items and the eliminates duplicates)
CREATE TABLE #Temp1
(
i int
)
CREATE TABLE #temp2
(
i int
)
INSERT INTO #Temp1
SELECT 3 UNION ALL
SELECT 1 UNION ALL
SELECT 8 UNION ALL
SELECT 2
INSERT INTO #Temp2
SELECT 7 UNION ALL
SELECT 1 UNION ALL
SELECT 5 UNION ALL
SELECT 6
SELECT * INTO #TEMP3
FROM (SELECT * FROM #Temp1 UNION ALL SELECT * FROM #temp2) X
UNION ALL adds all the records where as UNION adds only new/distinct records.
Since you are using UNION ALL and using DISTINCT soon after, I think you are looking for UNION
SELECT * INTO #TEMP4 FROM
(
SELECT * FROM #TEMP3
UNION --JUST UNION
SELECT * FROM #TEMP2
) AnotherTemp
Or you can simplify it as
SELECT * INTO #TEMP4 FROM
SELECT DISTINCT *
FROM Final
WHERE MomentId = #MomentId OR RowNum BETWEEN #StartRow AND #EndRow
I'm not familiar with SQL-Server, but you might get my idea
select *, 'A' tid, rownumber() tno from tableA
union all
select *, 'B', rownumber() from tableB
order by tid, tno;
This should get you all records of tableA in their specific order, followed by all records of tableB in their specific order.
I have a quick question about a select statement condition.
I have the following table with the following items. What I need to get is the object id that matches both type id's.
TypeId ObjectId
1 10
2 10
1 11
So I need to get both object 10 because it matches type id 1 and 2.
SELECT ObjectId
FROM Table
WHERE TypeId = 1
AND TypeId = 2
Obviously this doesn't work because it won't match both conditions for the same row. How do I perform this query?
Also note that I may pass in 2 or more type id's to narrow down the results.
Self-join:
SELECT t1.ObjectId
FROM Table AS t1
INNER JOIN Table AS t2
ON t1.ObjectId = t2.ObjectId
AND t1.TypeId = 1
AND t2.TypeId = 2
Note sure how you want the behavior to work when passing in values, but that's a start.
I upvoted the answer from #Cade Roux, and that's how I would do it.
But FWIW, here's an alternative solution:
SELECT ObjectId
FROM Table
WHERE TypeId IN (1, 2)
GROUP BY ObjectId
HAVING COUNT(*) = 2;
Assuming uniqueness over TypeId, ObjectId.
Re the comment from #Josh that he may need to search for three or more TypeId values:
The solution using JOIN requires a join per value you're searching for. The solution above using GROUP BY may be easier if you find yourself searching for an increasing number of values.
This code is written with Oracle in mind. It should be general enough for other flavors of SQL
select t1.ObjectId from Table t1
join Table t2 on t2.TypeId = 2 and t1.ObjectId = t2.ObjectId
where t1.TypeId = 1;
To add additional TypeIds, you just have to add another join:
select t1.ObjectId from Table t1
join Table t2 on t2.TypeId = 2 and t1.ObjectId = t2.ObjectId
join Table t3 on t3.TypeId = 3 and t1.ObjectId = t3.ObjectId
join Table t4 on t4.TypeId = 4 and t1.ObjectId = t4.ObjectId
where t1.TypeId = 1;
Important note: as you add more joins, performance will suffer a LOT.
In regards to Bill's answer you can change it to the following to get rid of the need to assume uniqueness:
SELECT ObjectId
FROM (SELECT distinct ObjectId, TypeId from Table)
WHERE TypeId IN (1, 2)
GROUP BY ObjectId
HAVING COUNT(*) = 2;
His way of doing it scales better as the number of types gets larger.
Try this
Sample Input:(Case 1)
declare #t table(Typeid int,ObjectId int)
insert into #t
select 1,10 union all select 2,10 union all
select 1,11
select * from #t
Sample Input:(Case 2)
declare #t table(Typeid int,ObjectId int)
insert into #t
select 1,10 union all select 2,10 union all
select 3,10 union all select 4,10 union all
select 5,10 union all select 6,10 union all
select 1,11 union all select 2,11 union all
select 3,11 union all select 4,11 union all
select 5,11 union all select 1,12 union all
select 2,12 union all select 3,12 union all
select 4,12 union all select 5,12 union all
select 6,12
select * from #t
Sample Input:(Case 3)[Duplicate entries are there]
declare #t table(Typeid int,ObjectId int)
insert into #t
select 1,10 union all select 2,10 union all
select 1,10 union all select 2,10 union all
select 3,10 union all select 4,10 union all
select 5,10 union all select 6,10 union all
select 1,11 union all select 2,11 union all
select 3,11 union all select 4,11 union all
select 5,11 union all select 1,12 union all
select 2,12 union all select 3,12 union all
select 4,12 union all select 5,12 union all
select 6,12 union all select 3,12
For case 1, the output should be 10
For case 2 & 3, the output should be 10 and 12
Query:
select X.ObjectId from
(
select
T.ObjectId
,count(ObjectId) cnt
from(select distinct ObjectId,Typeid from #t)T
where T.Typeid in(select Typeid from #t)
group by T.ObjectId )X
join (select max(Typeid) maxcnt from #t)Y
on X.cnt = Y.maxcnt