Postgresql: append two tables with different columns - sql

I would like to append one table to the other; both tables may have different columns. The result should be a table with all columns and where values do not exist, it should be a missing observation. The data are time series - which I am getting from different sources due to time span constraints - so I need to "stack" them on each other, but it could be that one or the other column is added or dropped off.
As there is a little overlap in the rows I am looking for a solution that would take the data of first table. The problem is then for those column not existing in table 1, they wouldn't exist either when I pick table 1 over table 2.
Current solution is to cut-off table 2 so there is no overlap.
table 1:
date AA BB CC DD
20100101 9 10 11 12
20100102 10 11 12 13
table 2:
date AA BB CC EE FF
20100102 99 99 10
20100103 11 12 13 14 10
20100104 12 13 14 15 11
and the result should be
date AA BB CC DD EE FF
20100101 9 10 11 12
20100102 10 11 12 13 99 10
20100103 11 12 13 14 10
20100104 12 13 14 15 11
So I do not in fact have anything to "join" on as suggested here: SQL union of two tables with different columns

coalesce function may be used like in the following :
select coalesce(t1.date,t2.date) date,
coalesce(t1.aa,t2.aa) aa,
coalesce(t1.bb,t2.bb) bb,
coalesce(t1.cc,t2.cc) cc,
t1.dd,
t2.ee,
t2.ff
from table1 t1 full outer join table2 t2 on ( t1.date = t2.date );
SQL Fiddle Demo

Related

T-SQL go through Dates

I have the following table:
Column1 Column2 Column3
04/07/2019 1
04/08/2019 2
04/09/2019 8
04/10/2019 9
04/11/2019 15
04/12/2019 16
04/13/2019 5
04/14/2019 6
04/15/2019 8
04/16/2019 9
04/17/2019 10
04/18/2019 11
04/19/2019 5
04/20/2019 5
04/21/2019 8
04/22/2019 8
04/23/2019 9
04/24/2019 10
04/25/2019 11
04/26/2019 12
04/27/2019 10
I need to find out a way to iterate through the values in column one and identify weeks which should start from Saturday - Sunday. So, in this example one iteration should be from the 14 - 20th. Or another iteration would be from the 7th through the 13th which is Saturday - Sunday. Then After identifying each week, I need to do some calculation on the other columns.The calculation would be updating Column3 if the total amount for Column2 within 1 week (Based on Column1 Saturday to Sunday) exceeds 40 or not. Then the same for the next iteration of week (Saturday - Sunday).
Desired Results:
Column1 Column2 Column3
04/07/2019 1 56
04/08/2019 2 56
04/09/2019 8 56
04/10/2019 9 56
04/11/2019 15 56
04/12/2019 16 56
04/13/2019 5 56
04/14/2019 6 54
04/15/2019 8 54
04/16/2019 9 54
04/17/2019 10 54
04/18/2019 11 54
04/19/2019 5 54
04/20/2019 5 54
04/21/2019 8 68
04/22/2019 8 68
04/23/2019 9 68
04/24/2019 10 68
04/25/2019 11 68
04/26/2019 12 68
04/27/2019 10 68
Please note: The data can range from 3 weeks to a few month. So, the code needs to capture the weeks for any specific range.
You can use datepart() to get the week of a date. You can then use the week to partition by in a windowed sum(). From there you can UPDATE the table joining a derived table that gets the sum like mentioned before. To make sure the week begins on Sunday issue a SET DATEFIRST 7 before the UPDATE.
SET DATEFIRST 7;
UPDATE t1
SET t1.column3 = t3.column3
FROM elbat t1
INNER JOIN (SELECT t2.column1,
sum(t2.column2) OVER (PARTITION BY datepart(week, t2.column1)) column3
FROM elbat t2) t3
ON t3.column1 = t1.column1;
db<>fiddle

transpose column to row oracle

I have a query returned value in this form (query return more than 50 columns).
1-99transval 100-200transval 200-300transval ... 1-99nontransval 100...
50 90 80 67 58
For a row value. I want these details to be converted into columns and take the following shape:
Range Transval NonTransval
1-99 50 67
100-200 90 58
In pure SQL, it will need a lot of coding because you will have to manually put the range as there is no relation between the values and the range at all. Had there been a relationship, you could use CASE expression and build the range dynamically.
SQL> WITH DATA AS
2 (SELECT 50 "1-99transval",
3 90 "100-200transval",
4 80 "200-300transval",
5 67 "1-99nontransval",
6 58 "100-200nontransval",
7 88 "200-300nontransval"
8 FROM dual
9 )
10 SELECT '1-99' range,
11 "1-99transval" transval,
12 "1-99nontransval" nontransval
13 FROM DATA
14 UNION
15 SELECT '100-200' range,
16 "100-200transval",
17 "100-200nontransval" nontransval
18 FROM DATA
19 UNION
20 SELECT '200-300' range,
21 "200-300transval",
22 "200-300nontransval" nontransval
23 FROM DATA;
RANGE TRANSVAL NONTRANSVAL
------- ---------- -----------
1-99 50 67
100-200 90 58
200-300 80 88
From Oracle database 11g Release 1 and above, you could use UNPIVOT
SQL> WITH DATA AS
2 (SELECT 50 "1-99transval",
3 90 "100-200transval",
4 80 "200-300transval",
5 67 "1-99nontransval",
6 58 "100-200nontransval",
7 88 "200-300nontransval"
8 FROM dual
9 )
10 SELECT *
11 FROM DATA
12 UNPIVOT( (transval,nontransval)
13 FOR RANGE IN ( ("1-99transval","1-99nontransval") AS '1-99'
14 ,("100-200transval","100-200nontransval") AS '100-200'
15 ,("200-300transval","200-300nontransval") AS '200-300'));
RANGE TRANSVAL NONTRANSVAL
------- ---------- -----------
1-99 50 67
100-200 90 58
200-300 80 88
Above, in your case you need to replace the WITH clause with your existing query as a sub-query. You need to include other columns in the UNION.
In PL/SQL, you could (ab)use EXECUTE IMMEDIATE and get the "range" by extracting the column names in dynamic sql.
Although, it would be much better to modify/rewrite your existing query which you have not shown yet.
If you are using Oracle 11g version then you can use the UNPIVOT feature.
CREATE TABLE DATA AS
SELECT 50 "1-99transval",
90 "100-200transval",
80 "200-300transval",
67 "1-99nontransval",
58 "100-200nontransval",
88 "200-300nontransval"
FROM dual
SELECT *
FROM DATA
UNPIVOT( (Transval,NonTransval) FOR Range IN ( ("1-99transval","1-99nontransval") as '1-99'
,("100-200transval","100-200nontransval") as '100-200'
,("200-300transval","200-300nontransval") as '200-300'))
http://sqlfiddle.com/#!4/c9747/3/0

How to fetch data according to date in sql

I have a table truck_data with columns truck_no, diesel_filled, source, destination, amount etc
I want to fetch only truck_no and diesel_filled in such way that it will show the details of diesel_filled in each truck through out the month..
Please tell me the SQL query for that - I had tried this query but it's not working
SELECT
truck_no, diesel_filled, date
FROM
truck-data
ORDER BY
date
Please help me out
Thanks in advance
I want output like this
truck_no 1 2 3 4 5 6 7 8 9 etc(date from 1 to 31))
---------------------------------------------------------------------------
xyz 25 22 33 33 22 22 22 0 0 (diesel filled in truck order by date)
pqr 25 25 22 11 22 00 22 55 22
abc 21 15 12 14 13 00 22 00 00
It's still quite unclear what you want. But I think you are mixing presentation and data
SELECT truck_no,diesel_filled,date
FROM truck-data
ORDER BY date
Will give you all rows ordered by date. Presumably you whant some filter on that to only show a specific month.
SELECT truck_no,diesel_filled,date
FROM truck-data
WHERE date >= 2014-10-05 AND date < 2014-11-01 ORDER BY date
To get all the rows for october this year. If date here is a DateTime column.
Then you could change it to:
SELECT truck_no,sum(diesel_filled),Day(date)
FROM truck-data
WHERE date >= 2014-10-05 AND date < 2014-11-01
GROUP BY truck_no
ORDER BY date"
That would give you only one row per day and truck. If disel_filled is a numeric value of some kind.
Then in your UI you would have to do the presentation in any way you prefer. For example in some kind of pivot table like your description above.
You could of course do that in SQL as well, but usually that is a job for the presentation layer.
If you really want to do in SQL you could look into: http://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx
If you'r using MsSql.

How do I loop through a table until condition reached

I have a table product, pick_qty, shortfall, location, loc_qty
Product Picked Qty Shortfall Location Location Qty
1742 4 58 1 15
1742 4 58 2 20
1742 4 58 3 15
1742 4 58 4 20
1742 4 58 5 20
1742 4 58 6 20
1742 4 58 7 15
1742 4 58 8 15
1742 4 58 9 15
1742 4 58 10 20
I want a report to loop around and show the number of locations and the quantity I need to drop to fulfil the shortfall for replenishment. So the report would look like this.
Product Picked Qty Shortfall Location Location Qty
1742 4 58 1 15
1742 4 58 2 20
1742 4 58 3 15
1742 4 58 4 20
Note that it is best not to think about SQL "looping through a table" and instead to think about it as operating on some subset of the rows in a table.
What it sounds like you need to do is create a running total that tells how many of the item you would have if you were to take all of them from a location and all of the locations that came before the current location and then check to see if that would give you enough of the item to fulfill the shortfall.
Based on your example data, the following query would work, though if Locations aren't actually numerics then you would need to add a row number column and tweak the query a bit to use the row number instead of the Location Number; It would still be very similar to the query below.
SELECT
Totals.Product, Totals.PickedQty, Totals.ShortFall, Totals.Location, Totals.LocationQty
FROM (
SELECT
TheTable.Product, TheTable.PickedQty, TheTable.ShortFall,
TheTable.Location, TheTable.LocationQty, SUM(ForRunningTotal.LocationQty) AS RunningTotal
FROM TheTable
JOIN TheTable ForRunningTotal ON TheTable.Product = ForRunningTotal.Product
AND TheTable.Location >= ForRunningTotal.Location
GROUP BY TheTable.Product, TheTable.PickedQty, TheTable.ShortFall, TheTable.Location, TheTable.LocationQty
) Totals
-- Note you could also change the join above so the running total is actually the count of only the rows above,
-- not including the current row; Then the WHERE clause below could be "Totals.RunningTotal < Totals.ShortFall".
-- I liked RunningTotal as the sum of this row and all prior, it seems more appropriate to me.
WHERE Totals.RunningTotal - Totals.LocationQty <= Totals.ShortFall
AND Totals.LocationQty > 0
Also - as long as you are reading my answer, an unrelated side-note: Based on the data you showed above, your database schema isn't normalized as far as it could be. It seems like the Picked Quantity and the ShortFall actually depend only on the Product, so that would be a table of its own, and then the Location Quantity depends on the Product and Location, so that would be a table of its own. I'm pointing it out because if your data contained different Picked Quantities/ShortFall for a single product, then the above query would break; This situation would be impossible with the normalized tables I mentioned.

Can't get unique values joining two tables

I have 2 tables that I need to join and select the unique rows from. Here is a sample of my data: (there are more columns)
tbl1:
MB# MBName PCCNo_PRI Primary_IP PCCNo_SEC Secondary_IP ID
100 name 0 10.1.9.10 30 10.1.9.10 1
103 name3 17 10.1.9.27 47 10.1.9.67 4
403 name13 17 10.1.9.27 47 10.1.9.67 14
tbl2:
RTU PCC#_PRI PCC#_SEC STATION ADDRESS
15 0 30 6
52 12 42 1
53* 17 47 1
54 18 48 1
63 9 39 2
69* 17 47 2
I need to join the two tables and get the unique RTU(s) in tbl2 for a given MB# in tbl1.
Query =
SELECT t1.MB#,t2.RTU,t2.[Device Manufacturer],t2.PCC#_PRI,t2.PCC#_SEC,t2.[STATION ADDRESS]
INTO C300_RTU_MASTERBLK_Map
FROM mbm_PCDIMasterBlk_tbl as t1, dbo.WOA_PCC_Conn_tbl as t2
WHERE t1.PCCNo_PRI = t2.PCC#_PRI
I am getting duplicate rows for tbl2 53 and 69 (* above). 53 ends up with 2 entries; one to 103 and one 403 (69 gets same). How can I query this for unique RTU(s) to MB#?
The duplicate rows appears because you join on "17" which gives 2 rows on each side
Then, as it stands, you can't with that SELECT list.
How do you decide which t1.MB# you want for the t2 columns?
There is no secondary JOIN column that I can see.
So the best you can get is use MAX (or MIN) to pick either 403 or 103.
SELECT
MAX(t1.MB#) AS MB#,
t2.RTU,t2.[Device Manufacturer],t2.PCC#_PRI,t2.PCC#_SEC,t2.[STATION ADDRESS]
INTO C300_RTU_MASTERBLK_Map
FROM
dbombm_PCDIMasterBlk_tbl as t1
JOIN
dbo.WOA_PCC_Conn_tbl as t2 ON t1.PCCNo_PRI = t2.PCC#_PRI
GROUP BY
t2.RTU,t2.[Device Manufacturer],t2.PCC#_PRI,t2.PCC#_SEC,t2.[STATION ADDRESS]