Right join on each row - tsql

Is there an easy way to do the following without having to recur to temporary tables or cursors?
“Table 1 right join Table 2, but for each row in Table 1.”
Eg:
Table 1, Row 1 right join Table 2.
Table 1, Row 2 right join Table 2.
Etc.
Thanks
Update 1
Sorry I should of explained in a bit more detail.
Table definitions:
Table1:
TABLE [dbo].[Table_1]
(
[id] [int],
[name] [nvarchar](max) NULL,
[id_table2] [int] NULL)
Table 2.
TABLE [dbo].[Table_2]
(
[id] [int] NOT NULL,
[code] [nvarchar](max) NULL, )
Table 1 data:
Table 1 Data:
1 Prov1 1
2 Prov2 2
NULL
NULL NULL
Table 2 data:
Table 2 Data:
1 01
2 02
3 03
4 04
5 05
NULL
NULL
If I do the following:
select * from Table_1 as t1
right join Table_2 as t2 on
t1.id_table2 =
t2.id
result:
1 Prov1 1 1 01
2 Prov2 2 2 02
NULL NULL NULL 3 03
NULL NULL NULL 4 04
NULL NULL NULL 5 05
Result I'd like:
"Right join on each table 1 row"
1 Prov1 1 1 01
1 Prov1 NULL 2 02
1 Prov1 NULL 3 03
1 Prov1 NULL 4 04
1 Prov1 NULL 5 05
2 Prov2 1 1 01
2 Prov2 NULL 2 02
2 Prov2 NULL 3 03
2 Prov2 NULL 4 04
2 Prov2 NULL 5 05

I think you should be looking for a CROSS JOIN instead of RIGHT JOIN.

Related

PostgreSQL- get records with unique column combination

I want to select the records that have a unique column combination in postgresql, however it doesn't seem to work with distinct as distinct only removes duplicates.
Example
ID A B
01 1 2
02 1 2
03 1 3
04 2 4
05 1 4
06 2 4
07 2 5
08 1 3
In this example row with ID 05 and 07 have unique combination AB, how can i get these records
SELECT ...
With NOT EXISTS:
select t.* from tablename t
where not exists (
select 1 from tablename
where id <> t.id and a = t.a and b = t.b
)
Or with COUNT() window function:
select t.id, t.a, t.b
from (
select *, count(id) over (partition by a, b) counter
from tablename
) t
where t.counter = 1
Or with aggregation:
select max(id) id, a, b
from tablename
group by a, b
having count(id) = 1
Or with a self LEFT join that excludes the matching rows:
select t.*
from tablename t left join tablename tt
on tt.id <> t.id and tt.a = t.a and tt.b = t.b
where tt.id is null
See the demo.
Results:
| id | a | b |
| --- | --- | --- |
| 05 | 1 | 4 |
| 07 | 2 | 5 |

Pivot Table in SQL (using Groupby)

I have a table structured as below
Customer_ID Sequence Comment_Code Comment
1 10 0 a
1 11 1 b
1 12 1 c
1 13 1 d
2 20 0 x
2 21 1 y
3 100 0 m
3 101 1 n
3 102 1 o
1 52 0 t
1 53 1 y
1 54 1 u
Sequence number is the unique number in the table
I want the output in SQL as below
Customer_ID Sequence
1 abcd
2 xy
3 mno
1 tyu
Can someone please help me with this. I can provide more details if required.
enter image description here
This looks like a simple gaps/islands problem.
-- Sample Data
DECLARE #table TABLE
(
Customer_ID INT,
[Sequence] INT,
Comment_Code INT,
Comment CHAR(1)
);
INSERT #table
(
Customer_ID,
[Sequence],
Comment_Code,
Comment
)
VALUES (1,10 ,0,'a'),(1,11 ,1,'b'),(1,12 ,1,'c'),(1,13 ,1,'d'),(2,20 ,0,'x'),(2,21 ,1,'y'),
(3,100,0,'m'),(3,101,1,'n'),(3,102,1,'o'),(1,52 ,0,'t'),(1,53 ,1,'y'),(1,54 ,1,'u');
-- Solution
WITH groups AS
(
SELECT
t.Customer_ID,
Grouper = [Sequence] - DENSE_RANK() OVER (ORDER BY [Sequence]),
t.Comment
FROM #table AS t
)
SELECT
g.Customer_ID,
[Sequence] =
(
SELECT g2.Comment+''
FROM groups AS g2
WHERE g.Customer_ID = g2.Customer_ID AND g.Grouper = g2.Grouper
FOR XML PATH('')
)
FROM groups AS g
GROUP BY g.Customer_ID, g.Grouper;
Returns:
Customer_ID Sequence
----------- ----------
1 abcd
1 tyu
2 xy
3 mno

Select first non-null value for multiple columns and different rows in PostgreSQL

I'm trying to create a view based off a table. I want to get a set of rows where there is an existing tax_id_no, with each row having the most recent information. So I'm ordering by timestamps descending. However, each tax_id_no can have multiple rows, and not every row will have all the information. So I want to get the first valid piece of information for each column. Right now I've got this:
SELECT * FROM
(
SELECT DISTINCT ON (store_id, tax_id_no)
event_id,
event_tstamp,
owner_id,
store_id,
tax_id_no,
first_value(year_built) OVER (ORDER BY year_built IS NULL, event_tstamp) AS year_built, --New
first_value(roof_replaced_year) OVER (ORDER BY roof_replaced_year IS NULL, event_tstamp) AS roof_replaced_year, --New
first_value(number_of_rooms) OVER (ORDER BY number_of_rooms IS NULL, event_tstamp) AS number_of_rooms, --New
FROM MySchema.Event
WHERE tax_id_no IS NOT NULL AND tax_id_no != ''
order by store_id, tax_id_no, event_tstamp DESC
) t1
WHERE owner_id IS NOT NULL OR owner_id != '';
This is getting the same first valid information for every row though. So instead of getting results like this, which is what I want:
event_id event_tstamp owner_id store_id tax_id_no year_built roof_replaced_year number_of_rooms
04 2016-05-12 123 02 12345 1996 2009 6
05 2017-02-02 245 02 23456 1970 1999 8
08 2017-03-03 578 03 34567 2002 2016 10
I'm getting this, which all the rows looking the same in the first_value columns:
event_id event_tstamp owner_id store_id tax_id_no year_built roof_replaced_year number_of_rooms
04 2016-05-12 123 02 12345 1996 2009 6
05 2017-02-02 245 02 23456 1996 2009 6
08 2017-03-03 578 03 34567 1996 2009 6
Is it possible to select a different first_value for each row? I was thinking I could do some kind of a join across multiple selects from the same table, but I'm not sure that would actually give me unique values for each row instead of just having the same problem again. There's also the length of time for such queries to consider, which so far have been prohibitively expensive.
You can use a partition in your window functions to group the rows before applying the function. That will generate a distinct result for each partition.
For example:
first_value(number_of_rooms) OVER (
PARTION BY tax_id_no
ORDER BY number_of_rooms IS NULL, event_tstamp
) AS number_of_rooms,

Ignore null values when using SQL Server 2012's Last_Value() function

I am using SQL Server 2012 and have a table of values that look like this. It is populated with event data.
FldType Date Price Size
--------------------------------------------
2 2012-08-22 00:02:01 9140 1048
0 2012-08-22 00:02:02 9140 77
1 2012-08-22 00:02:03 9150 281
2 2012-08-22 00:02:04 9140 1090
0 2012-08-22 00:02:05 9150 1
1 2012-08-22 00:02:06 9150 324
2 2012-08-22 00:02:07 9140 1063
I would like to track the lastest value for each of the 3 field types (0,1,2) so that the final output looks like this.
Date Price0 Size0 Price1 Size1 Price2 Size2
-----------------------------------------------------------------
2012-08-22 00:02:01 NULL NULL NULL NULL 9140 1048
2012-08-22 00:02:02 9140 77 NULL NULL 9140 1048
2012-08-22 00:02:03 9140 77 9150 281 9140 1048
2012-08-22 00:02:04 9140 77 9150 281 9140 1090
2012-08-22 00:02:05 9150 1 9150 281 9140 1090
2012-08-22 00:02:06 9150 1 9150 324 9140 1090
2012-08-22 00:02:07 9150 1 9150 324 9140 1063
Unfortunately, it is not ignoring subsequent null values so I get this instead.
Date Price0 Size0 Price1 Size1 Price2 Size2
-----------------------------------------------------------------
2012-08-22 00:02:01 NULL NULL NULL NULL 9140 1048
2012-08-22 00:02:02 9140 77 NULL NULL NULL NULL
2012-08-22 00:02:03 NULL NULL 9150 281 NULL NULL
2012-08-22 00:02:04 NULL NULL NULL NULL 9140 1090
2012-08-22 00:02:05 9150 1 NULL NULL NULL NULL
2012-08-22 00:02:06 NULL NULL 9150 324 NULL NULL
2012-08-22 00:02:07 NULL NULL NULL NULL 9140 1063
My current query looks like this
SELECT [Date],
LAST_VALUE(Price0) OVER (PARTITION BY FldType ORDER BY [Date] ) AS Price0,
LAST_VALUE(Size0) OVER (PARTITION BY FldType ORDER BY [Date]) AS Size0,
LAST_VALUE(Price1) OVER (PARTITION BY FldType ORDER BY [Date] ) AS Price1,
LAST_VALUE(Size1) OVER (PARTITION BY FldType ORDER BY [Date]) AS Size1,
LAST_VALUE(Price2) OVER (PARTITION BY FldType ORDER BY [Date] ) AS Price2,
LAST_VALUE(Size2) OVER (PARTITION BY FldType ORDER BY [Date]) AS Size2
FROM (
SELECT FldType, [Date], Price, Size,
CASE WHEN FldType = 0 THEN Price END as Price0,
CASE WHEN FldType = 0 THEN Size END as Size0,
CASE WHEN FldType = 1 THEN Price END as Price1,
CASE WHEN FldType = 1 THEN Size END as Size1,
CASE WHEN FldType = 2 THEN Price END as Price2,
CASE WHEN FldType = 2 THEN Size END as Size2
FROM [RawData].[dbo].[Events]
) as T1
ORDER BY [Date]
Is there some way to have SQL Server 2012 ignore null values when determining the lastest value? Or is there a better approach not using Last_Value() function?
To summarize I am trying to achieve two thing.
Split the Price and Size columns into 6 columns (2 columns x 3 field types)
Keep track of the latest value in each of these columns.
Any suggestions would be apprciated.
I'm not sure you can do it with LAST_VALUE, unless you add a PIVOT maybe.
Also, you need to treat Size and Price separately because they come from different rows. So, this achieves what you want be breaking it down.
DECLARE #source TABLE (FldType int, DateCol DateTime, Price int, Size int);
INSERT #source VALUES
(2, '2012-08-22 00:02:01', 9140, 1048),(0, '2012-08-22 00:02:02', 9140, 77),
(1, '2012-08-22 00:02:03', 9150, 281),(2, '2012-08-22 00:02:04', 9140, 1090),
(0, '2012-08-22 00:02:05', 9150, 1),(1, '2012-08-22 00:02:06', 9150, 324),
(2, '2012-08-22 00:02:07', 9140, 1063);
SELECT
S.DateCol, Xp0.Price0, Xs0.Size0, Xp1.Price1, Xs1.Size1, Xp2.Price2, Xs2.Size2
FROM
#source S
OUTER APPLY
(SELECT TOP 1 S0.Price AS Price0 FROM #source S0 WHERE S0.FldType = 0 AND S0.DateCol <= S.DateCol ORDER BY S0.DateCol DESC) Xp0
OUTER APPLY
(SELECT TOP 1 S1.Price AS Price1 FROM #source S1 WHERE S1.FldType = 1 AND S1.DateCol <= S.DateCol ORDER BY S1.DateCol DESC) Xp1
OUTER APPLY
(SELECT TOP 1 S2.Price AS Price2 FROM #source S2 WHERE S2.FldType = 2 AND S2.DateCol <= S.DateCol ORDER BY S2.DateCol DESC) Xp2
OUTER APPLY
(SELECT TOP 1 S0.Size AS Size0 FROM #source S0 WHERE S0.FldType = 0 AND S0.DateCol <= S.DateCol ORDER BY S0.DateCol DESC) Xs0
OUTER APPLY
(SELECT TOP 1 S1.Size AS Size1 FROM #source S1 WHERE S1.FldType = 1 AND S1.DateCol <= S.DateCol ORDER BY S1.DateCol DESC) Xs1
OUTER APPLY
(SELECT TOP 1 S2.Size AS Size2 FROM #source S2 WHERE S2.FldType = 2 AND S2.DateCol <= S.DateCol ORDER BY S2.DateCol DESC) Xs2
ORDER BY
DateCol;
The other way is to maintain a separate table via triggers or some ETL that does it the summary for you.

How do I add totals/subtotals to a set of results without grouping the row data?

I'm constructing a SQL query for a business report. I need to have both subtotals (grouped by file number) and grand totals on the report.
I'm entering unknown SQL territory, so this is a bit of a first attempt. The query I made is almost working. The only problem is that the entries are being grouped -- I need them separated in the report.
Here is my sample data:
FileNumber Date Cost Charge
3 Dec 22/09 5 10
3 Jan 13/10 6 15
3B Mar 28/10 1 3
3B Mar 28/10 5 10
When I run this query
SELECT
CASE
WHEN (GROUPING(FileNumber) = 1) THEN NULL
ELSE FileNumber
END AS FileNumber,
CASE
WHEN (GROUPING(Date) = 1) THEN NULL
ELSE Date
END AS Date,
SUM(Cost) AS Cost,
SUM(Charge) AS Charge
FROM SubtotalTesting
GROUP BY FileNumber, Date WITH ROLLUP
ORDER BY
(CASE WHEN FileNumber IS NULL THEN 1 ELSE 0 END), -- Put NULLs after data
FileNumber,
(CASE WHEN Date IS NULL THEN 1 ELSE 0 END), -- Put NULLs after data
Date
I get the following:
FileNumber Date Cost Charge
3 Dec 22/09 5 10
3 Jan 13/10 6 15
3 NULL 11 25
3B Mar 28/10 6 13 <--
3B NULL 6 13
NULL NULL 17 38
What I want is:
FileNumber Date Cost Charge
3 Dec 22/09 5 10
3 Jan 13/10 6 15
3 NULL 11 25
3B Mar 28/10 1 3 <--
3B Mar 28/10 5 10 <--
3B NULL 6 13
NULL NULL 17 38
I can clearly see why the entries are being grouped, but I have no idea how to separate them while still returning the subtotals and grand total.
I'm a bit green when it comes to doing advanced SQL queries like this, so if I'm taking the wrong approach to the problem by using WITH ROLLUP, please suggest some preferred alternatives -- you don't have to write the whole query for me, I just need some direction. Thanks!
WITH SubtotalTesting (FileNumber, Date, Cost, Charge) AS
(
SELECT '3', CAST('2009-22-12' AS DATETIME), 5, 10
UNION ALL
SELECT '3', '2010-13-06', 6, 15
UNION ALL
SELECT '3B', '2010-28-03', 1, 3
UNION ALL
SELECT '3B', '2010-28-03', 5, 10
),
q AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY filenumber) AS rn
FROM SubTotalTesting
)
SELECT rn,
CASE
WHEN (GROUPING(FileNumber) = 1) THEN NULL
ELSE FileNumber
END AS FileNumber,
CASE
WHEN (GROUPING(Date) = 1) THEN NULL
ELSE Date
END AS Date,
SUM(Cost) AS Cost,
SUM(Charge) AS Charge
FROM q
GROUP BY
FileNumber, Date, rn WITH ROLLUP
HAVING GROUPING(rn) <= GROUPING(Date)
ORDER BY
(CASE WHEN FileNumber IS NULL THEN 1 ELSE 0 END),
FileNumber,
(CASE WHEN Date IS NULL THEN 1 ELSE 0 END),
Date