How can I do calculations with previous defined columns in PostgreSQL? - postgresql

I'm currently trying to calculate a column using previous declared columns. I think that would work in MySQL, but I'm unsure how do do that in PostgreSQL.
My Statement looks like this:
SELECT customerNumber, customerName, (
SELECT COALESCE(SUM(payments.amount), 0)
FROM payments
WHERE customers.customerNumber = payments.customerNumber
) as totalOfPaymentsMade,(
SELECT COALESCE(SUM(orderdetails.priceeach * orderdetails.quantityordered), 0)
FROM orders
LEFT JOIN orderdetails ON orderdetails.ordernumber = orders.ordernumber
WHERE customers.customerNumber = orders.customerNumber
) as totalValueOfAllOrdersMade, creditLimit, creditLimit + totalOfPaymentsMade - totalValueOfAllOrdersMade as amountOfAvailableCredit
FROM customers
ORDER BY customerNumber
I get this error message: column "totalofpaymentsmade" does not exist
LINE 11: ...lValueOfAllOrdersMade, creditLimit, creditLimit + totalOfPay...

Try this:
SELECT
*,
creditLimit + totalOfPaymentsMade - totalValueOfAllOrdersMade
as amountOfAvailableCredit
from
(
SELECT
customerNumber,
customerName,
creditLimit,
(
SELECT COALESCE(SUM(payments.amount), 0)
FROM payments
WHERE customers.customerNumber = payments.customerNumber
)
as totalOfPaymentsMade,
(
SELECT COALESCE(SUM(orderdetails.priceeach * orderdetails.quantityordered), 0)
FROM orders
LEFT JOIN orderdetails ON orderdetails.ordernumber = orders.ordernumber
WHERE customers.customerNumber = orders.customerNumber
)
as totalValueOfAllOrdersMade
FROM customers
) a
ORDER BY customerNumber

Related

How To Properly Use Lateral Joins In PSQL

When I run the command below, there is a syntax error highlighted at UNION on the last line. I am really not sure why.
SELECT *
FROM (
SELECT (final_exp.deploymentyear + number) AS deploymentyear1,
(final_exp.deploymentyear + number) - final_exp.deploymentyear AS diff,
final_exp.*
FROM (
SELECT number
FROM hubb."spt_values"
WHERE type = 'P'
AND (
2000 + number) <= 2023 ) s
LEFT JOIN lateral (
SELECT *
FROM final_exp
WHERE (
final_exp.deploymentyear + number) < 2023
AND NOT EXISTS
(
SELECT 1
FROM final_exp g
WHERE g.deploymentyear = (final_exp.deploymentyear + number)
AND g.sacstate = final_exp.sacstate
AND g.fund = final_exp.fund
AND g.companyname = final_exp.companyname )
AND diff = 1 )df
UNION
I verified parentheses and comments and can't find where the issue might be coming from. Is it the lateral join?
You are missing the join condition for the Join portion. You need to join the "S" sub query and the join like "ON df.some_column=s.some_column"

SQL Server - Select with Group By together Raw_Number

I'm using SQL Server 2000 (80). So, it's not possible to use the LAG function.
I have a code a data set with four columns:
Purchase_Date
Facility_no
Seller_id
Sale_id
I need to identify missing Sale_ids. So every sale_id is a 100% sequential, so the should not be any gaps in order.
This code works for a specific date and store if specified. But i need to work on entire data set looping looping through every facility_id and every seller_id for ever purchase_date
declare #MAXCOUNT int
set #MAXCOUNT =
(
select MAX(Sale_Id)
from #table
where
Facility_no in (124) and
Purchase_date = '2/7/2020'
and Seller_id = 1
)
;WITH TRX_COUNT AS
(
SELECT 1 AS Number
union all
select Number + 1 from TRX_COUNT
where Number < #MAXCOUNT
)
select * from TRX_COUNT
where
Number NOT IN
(
select Sale_Id
from #table
where
Facility_no in (124)
and Purchase_Date = '2/7/2020'
and seller_id = 1
)
order by Number
OPTION (maxrecursion 0)
My Dataset
This column:
case when
Sale_Id=0 or 1=Sale_Id-LAG(Sale_Id) over (partition by Facility_no, Purchase_Date, Seller_id)
then 'OK' else 'Previous Missing' end
will tell you which Seller_Ids have some sale missing. If you want to go a step further and have exactly your desired output, then filter out and distinct the 'Previous Missing' ones, and join with a tally table on not exists.
Edit: OP mentions in comments they can't use LAG(). My suggestion, then, would be:
Make a temp table that that has the max(sale_id) group by facility/seller_id
Then you can get your missing results by this pseudocode query:
Select ...
from temptable t
inner join tally N on t.maxsale <=N.num
where not exists( select ... from sourcetable s where s.facility=t.facility and s.seller=t.seller and s.sale=N.num)
> because the only way to "construct" nonexisting combinations is to construct them all and just remove the existing ones.
This one worked out
; WITH cte_Rn AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY Facility_no, Purchase_Date, Seller_id ORDER BY Purchase_Date) AS [Rn_Num]
FROM (
SELECT
Facility_no,
Purchase_Date,
Seller_id,
Sale_id
FROM MyTable WITH (NOLOCK)
) a
)
, cte_Rn_0 as (
SELECT
Facility_no,
Purchase_Date,
Seller_id,
Sale_id,
-- [Rn_Num] AS 'Skipped Sale'
-- , case when Sale_id = 0 Then [Rn_Num] - 1 Else [Rn_Num] End AS 'Skipped Sale for 0'
, [Rn_Num] - 1 AS 'Skipped Sale for 0'
FROM cte_Rn a
)
SELECT
Facility_no,
Purchase_Date,
Seller_id,
Sale_id,
-- [Skipped Sale],
[Skipped Sale for 0]
FROM cte_Rn_0 a
WHERE NOT EXISTS
(
select * from cte_Rn_0 b
where b.Sale_id = a.[Skipped Sale for 0]
and a.Facility_no = b.Facility_no
and a.Purchase_Date = b.Purchase_Date
and a.Seller_id = b.Seller_id
)
--ORDER BY Purchase_Date ASC

How to SELECT only the "nth" record from a query result?

I have a T-SQL query that return X records ordered.
I want to get only on record , for instance, only the 5th record from that result: how ?
Thanks
For that you have to update your query.
I.e in oracle we have rownum that assign rownumber to every row.
You can do like this,
Select * from(
Select a.*, rownum as n from your table) where n = 3;
Something like this.
Try this:
WITH NumberedTable AS
(
SELECT
RowNo = ROW_NUMBER() OVER(ORDER BY <'Order Column here'>)
, *
FROM <'Table Name here'>
)
SELECT *
FROM NumberedTable
WHERE RowNo = <'Record No. here'>

Select not null column in full join postgresql

I have 3 tables:
with current_exclusive as(
select id_station, area_type,
count(*) as total_entries
from c1169.data_cashier
where id_station IN(2439,2441,2443,2445,2447,2449) and date >= '2017-10-30' and date <= '2017-12-30'
group by id_station, area_type
), current_table as(
select id_station, area_type,
sum(total_time) filter (where previous_status = 1) as total_time
from c1169.data_table
where id_station IN(2439,2441,2443,2445,2447,2449) and date >= '2017-10-30' and date < '2017-12-30'
group by id_station, area_type
), current_cashier as(
select id_station, area_type,
sum(1) as total_transactions
from c1169.data_cashier
where id_station IN(2439,2441,2443,2445,2447,2449) and date >= '2017-10-30' and date < '2017-12-30'
group by id_station, area_type
)
select *
from current_exclusive
full join current_table on current_exclusive.id_station = current_table.id_station and current_exclusive.area_type = current_table.area_type
full join current_cashier on current_exclusive.id_station = current_cashier.id_station and current_exclusive.area_type = current_cashier.area_type
and the result is:
but my expected result is:
Are there any way to select * and show the expected result? Because when I do full join then id_station and area_type can be null in some tables, so it very hard to choose which column is not null.
Like: select case id_station is not null then id_station else id_station1 end, but I have up to 10 tables so can not do in select case
Use USING, per the documentation:
USING ( join_column [, ...] )
A clause of the form USING ( a, b, ... ) is shorthand for ON left_table.a = right_table.a AND left_table.b = right_table.b .... Also, USING implies that only one of each pair of equivalent columns will be included in the join output, not both.
select *
from current_exclusive
full join current_table using (id_station, area_type)
full join current_cashier using (id_station, area_type)
You cannot accomplish anything if you insist on using select *, since you are getting the values from different tables.
The option you have is to include a COALESCE block which gives you the first non-null value from the list of columns.
So, you could use.
select COALESCE( current_exclusive.id_station, current_table.id_station, current_cashier.id_station ) as id_station ,
COALESCE( current_exclusive.area_type , current_table.area_type, current_cashier.area_type ) as area_type ,.....
...
from current_exclusive
full join current_table..
...

Difficult query (DB2)

Suppose I have a table called spitems with the following fields:
spitemid (unique key)
modifiedon (timestamp)
parentid
a number of other unsignificant fields
What I want to retrieve, is the spitem rows with the highest modifiedon day for each parentid.
However, be aware that the modifiedon timestamp is not unique, so it is possible that for one parent id, there are two spitemids with the same modifiedon timestamp. In that case, I need one of these two spitemids listed, I don't care which one.
So to be clear: the list I return should contain all the parentids once and only once.
update
meeting over, here is my shot:
select *
from table
join where spitmid in
(select max(spitmid)
from table
join
(select parentid, max(modifiedon) as d from table group by parentid) inlist
on table.parentid = inlist.parentid and table.modifiedon = inlist.d
group by parentid, datemodified
)
old entry
not sure if this is different on DB2, here it is for sql server.
select *
from table
join (select parentid, max(modifiedon) as d from table group by parentid) as toplist on
table.parentid = toplist.parentid and table.modifiedon = toplist.d
hmm... this will return more than one for the dups... can't fix it now, have to go to a meeting.
Based on your requirements, following should get you the latest items.
SELECT t1.*
FROM Table t1
INNER JOIN (
SELECT spitemid = MAX(t1.spitemid)
FROM Table t1
INNER JOIN (
SELECT parentid, modifiedon = MAX(modifiedon)
FROM Table
GROUP BY parentid
) t2 ON t2.parentid = t1.parentid
AND t2.modifiedon = t1.modifiedon
GROUP BY t1.parentid, t1.modifiedon
) t2 ON t2.spitemid = t1.spitemid
You can do it with two nested subqueries. The first gets max modifiedon for each parentid, and then the second gets max spitemid for each parentid/modifiedon group.
SELECT *
FROM spitems
WHERE spitemid IN
(
SELECT parentid, modifiedon, max(spitemid) spitemid
FROM (
SELECT parentid, MAX(modifiedon) modifiedon
FROM spitems
GROUP BY parentid
) A
GROUP BY parentid, modifiedon
)
A common table expression will give you the opportunity to number the rows before you issue the final SELECT.
WITH items AS
(
SELECT spitemid, parentid, modifiedon,
ROWNUMBER() OVER (PARTITION BY parentid ORDER BY modifiedon DESC) AS rnum
FROM yourTable
)
SELECT spitemid, parentid, modifiedon FROM items WHERE rnum = 1
;
SELECT sr.receiving_id, sc.collection_id FROM stock_collection as sc, stock_requisation as srq, stock_receiving as sr WHERE (sc.stock_id = '" & strStockID & "' AND sc.datemm_issued = '" & strMM & "' AND sc.qty_issued >= 0 AND sc.collection_id = srq.requisition_id AND srq.active_status = 'Active') OR (sr.stock_id = '" & strStockID & "' AND sr.datemm_received = '" & strMM & "' AND sr.qty_received >= 0)