How to get Odoo Inventory adjustment value through SQL - sql

I am working on a custom stock valuation module and in one model I am trying to get adjustment value for a lot - product - warehouse wise of the previous day.
QUERY 1
SELECT COUNT(*)
FROM
(
SELECT stock_inventory.date AS stock_adjustment_date,
stock_move_line.lot_id,
stock_move_line.product_id,
SUM(stock_move_line.qty_done) total_stock_adjustment
FROM stock_move_line
LEFT JOIN stock_move ON stock_move_line.move_id = stock_move.id
LEFT JOIN stock_inventory ON stock_move.inventory_id = stock_inventory.id
WHERE stock_move.inventory_id IS NOT NULL
AND stock_move_line.location_id = 5
AND stock_move_line.location_dest_id = 13
AND stock_move_line.lot_id IS NOT NULL
GROUP BY stock_move_line.lot_id, stock_move_line.product_id, stock_inventory.date
ORDER BY total_stock_adjustment DESC
)
testTable;
QUERY 2
SELECT COUNT(*)
FROM
(
SELECT stock_inventory.date AS stock_adjustment_date,
stock_move_line.lot_id,
stock_move_line.product_id,
SUM(stock_move_line.qty_done) total_stock_adjustment
FROM stock_move_line
LEFT JOIN stock_move ON stock_move_line.move_id = stock_move.id
LEFT JOIN stock_inventory ON stock_move.inventory_id = stock_inventory.id
WHERE stock_move.inventory_id IS NOT NULL
AND stock_move_line.location_id = 13
AND stock_move_line.location_dest_id = 5
AND stock_move_line.lot_id IS NOT NULL
GROUP BY stock_move_line.lot_id, stock_move_line.product_id, stock_inventory.date
ORDER BY total_stock_adjustment DESC
)
testTable;
Why these both queries returning same count 14,849 ?
13 is the warehouse ID and 5 is the virtual location used for adjustment. What I am doing wrong here?

Related

Query on large table

I have the following query -
SELECT n.fname
,ii.render AS practitioner_npi
,n.address AS address1
,substring(n.postal,0,6) AS zip
,substring(n.postal,6,4) AS zip4
,ii.count AS count
FROM
(
SELECT render, count(*) AS count
FROM dx sl
JOIN annual caq
ON DATE_TRUNC('quarter', date_of_service::date) >= caq.start
JOIN entities n
ON sl.render = n.npi
WHERE dx_cd IN (
SELECT DISTINCT dx_cd
FROM dx_per_code pc
JOIN bucket bac
ON pc.code = bac.hcpccode
WHERE
bucketname = 'something'
AND dx_rank BETWEEN 1 AND 5
)
AND n.npi_type = '1'
GROUP BY render
)
ii
JOIN npi n ON n.npi = ii.render
LEFT JOIN taxonomy t ON t.code = n.taxonomy
ORDER BY ii.count DESC;
The dx table does not have any indexes and contains approax 8B records. This query currently takes 20 minutes to run. What indexes/optimizations can I make to get this to run faster?

ORA-00904: "Q"."ITEM_NO": invalid identifier - Oracle SQL group by issue

I have this query to fetch item no's and their quantities filtered by a specific unit.
select q.item_no, sum(q.quantity) from item_unit_quantity q
where q.unit_no = 'PH00000096' group by q.item_no
Now I want to add price column which I get from another two tables
There is a condition, Price is always the maximum of the latest three GRN dates.
select max(price) from (select price from grn_item gi join grn g on gi.grn_no = g.grn_no
where gi.item_no = 'IT00001896' order by g.grn_date desc) where rownum <= 3
When I combined the queries as below,
select q.item_no, sum(q.quantity),
(select max(price) from (select price from grn_item gi join grn g on gi.grn_no = g.grn_no
where gi.item_no = q.item_no order by g.grn_date desc) where rownum <= 3) "PRICE"
from item_unit_quantity q where q.unit_no = 'PH00000096' group by q.item_no
I get
ORA-00904: "Q"."ITEM_NO": invalid identifier
But if I change the above as "gi.item_no = 'IT00001896'" I get
ITEM_NO | Sum(Quantity) | Price
--------------------------------------
IT00012824 | 14 | 3.68
IT00006345 | 494 | 3.68
IT00001896 | 5 | 3.68
I still want to display the Item no, Item quantity and price for each Item no in this query, how can I do this?
Your question is a bit hard to follow without sample data. However, subqueries with GROUP BY can be finicky. A simple solution is to move the subquery to the FROM clause:
select q.item_no, sum(q.quantity), max(max_price)
from item_unit_quantity q left join
(select gi.item_no, max(g.price) as max_price
from grn_item gi join
grn g
on gi.grn_no = g.grn_no
group by gi.item_no
) gi
on gi.item_no = q.item_no
where q.unit_no = 'PH00000096'
group by q.item_no

How to force postgres to return 0 even if there are no rows matching query, using coalesce, group by and join

I've been trying hopelessly to get the following SQL statement to return the query results and default to 0 if there are no rows matching the query.
This is the intended result:
vol | year
-------+------
0 | 2018
Instead I get:
vol | year
-----+------
(0 rows)
Here is the sql statement:
select coalesce(vol,0) as vol, year
from (select sum(vol) as vol, year
from schema.fact_data
join schema.period_data
on schema.fact_data.period_tag = schema.period_data.tag
join schema.product_data
on schema.fact_data.product_tag =
schema.product_data.tag
join schema.market_data
on schema.fact_data.market_tag = schema.market_data.tag
where "retailer"='MadeUpRetailer'
and "product_tag"='FakeProductTag'
and "year"='2018' group by year
) as DerivedTable;
I know the query works because it returns data when there is data. Just doesn't default to 0 as intended...
Any help in finding why this is the case would be much appreciated!
Using your subquery DerivedTable, you could write:
SELECT coalesce(DerivedTable.vol, 0) AS vol,
y.year
FROM (VALUES ('2018'::text)) AS y(year)
LEFT JOIN (SELECT ...) AS DerivedTable
ON DerivedTable.year = y.year;
Remove the GROUP BY (and the outer query):
select 2018 as year, coalesce(sum(vol), 0) as vol
from schema.fact_data f join
schema.period_data p
on f.period_tag = p.tag join
schema.product_data pr
on f.product_tag = pr.tag join
schema.market_data m
on fd.market_tag = m.tag
where "retailer" = 'MadeUpRetailer' and
"product_tag" = 'FakeProductTag' and
"year" = '2018';
An aggregation query with no GROUP BY always returns exactly one row, so this should do what you want.
EDIT:
The query would look something like this:
select v.yyyy as year, coalesce(sum(vol), 0) as vol
from (values (2018), (2019)) v(yyyy) left join
schema.fact_data f
on f.year = v.yyyy left join -- this is just an example. I have no idea where year is coming from
schema.period_data p
on f.period_tag = p.tag left join
schema.product_data pr
on f.product_tag = pr.tag left join
schema.market_data m
on fd.market_tag = m.tag
group by v.yyyy
However, you have to move the where conditions to the appropriate on clauses. I have no idea where the columns are coming from.
From the code you posted it is not clear in which table you have the year column.
You can use UNION to fetch just 1 row in case there are no rows in that table for the year 2018 like this:
select sum(vol) as vol, year
from schema.fact_data innrt join schema.period_data
on schema.fact_data.period_tag = schema.period_data.tag
inner join schema.product_data
on schema.fact_data.product_tag = schema.product_data.tag
inner join schema.market_data
on schema.fact_data.market_tag = schema.market_data.tag
where
"retailer"='MadeUpRetailer' and
"product_tag"='FakeProductTag' and
"year"='2018'
group by "year"
union
select 0 as vol, '2018' as year
where not exists (
select 1 from tablename where "year" = '2018'
)
In case there are rows for the year 2018, then nothing will be fetched by the 2nd query,

How to use alias of a subquery to get the running total?

I have a UNION of 3 tables for calculating some balance and I need to get the running SUM of that balance but I can't use PARTITION OVER, because I must do it with a sql query that can work in Access.
My problem is that I cannot use JOIN on an alias subquery, it won't work.
How can I use alias in a JOIN to get the running total?
Or any other way to get the SUM that is not with PARTITION OVER, because it does not exist in Access.
This is my code so far:
SELECT korisnik_id, imePrezime, datum, Dug, Pot, (Dug - Pot) AS Balance
FROM (
SELECT korisnik_id, k.imePrezime, r.datum, SUM(IIF(u.jedinstven = 1, r.cena, k.kvadratura * r.cena)) AS Dug, '0' AS Pot
FROM Racun r
INNER JOIN Usluge u ON r.usluga_id = u.ID
INNER JOIN Korisnik k ON r.korisnik_id = k.ID
WHERE korisnik_id = 1
AND r.zgrada_id = 1
AND r.mesec = 1
AND r.godina = 2017
GROUP BY korisnik_id, k.imePrezime, r.datum
UNION ALL
SELECT korisnik_id, k.imePrezime, rp.datum, SUM(IIF(u.jedinstven = 1, rp.cena, k.kvadratura * rp.cena)) AS Dug, '0' AS Pot
FROM RacunP rp
INNER JOIN Usluge u ON rp.usluga_id = u.ID
INNER JOIN Korisnik k ON rp.korisnik_id = k.ID
WHERE korisnik_id = 1
AND rp.zgrada_id = 1
AND rp.mesec = 1
AND rp.godina = 2017
GROUP BY korisnik_id, k.imePrezime, rp.datum
UNION ALL
SELECT uu.korisnik_id, k.imePrezime, uu.datum, '0' AS Dug, SUM(uu.iznos) AS Pot
FROM UnosUplata uu
INNER JOIN Korisnik k ON uu.korisnik_id = k.ID
WHERE korisnik_id = 1
GROUP BY uu.korisnik_id, k.imePrezime, uu.datum
) AS a
ORDER BY korisnik_id
You can save a query (let's name it Query1) for the UNION of the 3 tables and then create another query that returns each row in the first query and calculates the sum of the rows that are before it (optionally checking that they are in the same group).
It should be something like this:
SELECT *, (
SELECT SUM(Value) FROM Query1 AS b
WHERE b.GroupNumber=a.GroupNumber
AND b.Position<=a.Position
) AS RunningSum
FROM Query1 AS a
However, it's more efficient to do that in the report.

returning only the most recent record in dataset

I have a query returning data for several dates.
I want to return only record with the most recent date in the field SAPOD (the date is in fact CYYMMDD where C=0 before 2000 and 1 after 2000 and I can show this as YYYYMMDD using SAPOD=Case when LEFT(SAPOD,1)=1 then '20' else '19' end + SUBSTRING(cast(sapod as nvarchar(7)),2,7))
here is my query:
SELECT GFCUS, Ne.NEEAN, SCDLE, SAPOD, SATCD,CUS.GFCUN, BGCFN1,
BGCFN2, BGCFN3, SV.SVCSA, SV.SVNA1, SV.SVNA2, SV.SVNA3,
SV.SVNA4, SV.SVNA5, SV.SVPZIP, SV.NONUK
FROM SCPF ACC
INNER JOIN GFPF CUS ON GFCPNC = SCAN
LEFT OUTER JOIN SXPF SEQ ON SXCUS = GFCUS AND SXPRIM = ''
LEFT OUTER JOIN SVPFClean SV ON SVSEQ = SXSEQ
LEFT OUTER JOIN BGPF ON BGCUS = GFCUS AND BGCLC = GFCLC
LEFT OUTER JOIN NEPF NE ON SCAB=NE.NEAB and SCAN=ne.NEAN and SCAS=ne.NEAS
LEFT OUTER JOIN SAPF SA ON SCAB=SAAB and SCAN=SAAN and SCAS=SAAS
WHERE
(SATCD>500 and
scsac='IV' and
scbal = 0 and
scai30<>'Y' and
scai14<>'Y' and
not exists(select * from v5pf where v5and=scan and v5bal<>0))
GROUP BY GFCUS, Ne.NEEAN, SCDLE, SAPOD, SATCD,
CUS.GFCUN, BGCFN1, BGCFN2, BGCFN3, SV.SVCSA,
SV.SVNA1, SV.SVNA2, SV.SVNA3, SV.SVNA4, SV.SVNA5, SV.SVPZIP, SV.NONUK
ORDER BY MAX(SCAN) ASC, SAPOD DESC
I am getting results like the below where there are several transactions by a customer, and we only want to show the data of the most recent transaction:
So how can I show just the most recent transaction? Is this a case where I should use an OUTER APPLY or CROSS APPY?
EDIT:
Sorry I should clarify that I need the most recent date for each of the unique records in the field NEEAN which is the Account number
You can use ROW_NUMBER() as follows:
SELECT
ROW_NUMBER() OVER (PARTITION BY Ne.NEEAN ORDER BY SAPOD DESC) AS [Row],
GFCUS, Ne.NEEAN, SCDLE, SAPOD, SATCD,CUS.GFCUN, BGCFN1,
BGCFN2, BGCFN3, SV.SVCSA, SV.SVNA1, SV.SVNA2, SV.SVNA3,
SV.SVNA4, SV.SVNA5, SV.SVPZIP, SV.NONUK
FROM SCPF ACC
INNER JOIN GFPF CUS ON GFCPNC = SCAN
LEFT OUTER JOIN SXPF SEQ ON SXCUS = GFCUS AND SXPRIM = ''
LEFT OUTER JOIN SVPFClean SV ON SVSEQ = SXSEQ
LEFT OUTER JOIN BGPF ON BGCUS = GFCUS AND BGCLC = GFCLC
LEFT OUTER JOIN NEPF NE ON SCAB=NE.NEAB and SCAN=ne.NEAN and SCAS=ne.NEAS
LEFT OUTER JOIN SAPF SA ON SCAB=SAAB and SCAN=SAAN and SCAS=SAAS
WHERE
(SATCD>500 and
scsac='IV' and
scbal = 0 and
scai30<>'Y' and
scai14<>'Y' and
not exists(select * from v5pf where v5and=scan and v5bal<>0)) and
[Row] = 1
GROUP BY GFCUS, Ne.NEEAN, SCDLE, SAPOD, SATCD,
CUS.GFCUN, BGCFN1, BGCFN2, BGCFN3, SV.SVCSA,
SV.SVNA1, SV.SVNA2, SV.SVNA3, SV.SVNA4, SV.SVNA5, SV.SVPZIP, SV.NONUK
ORDER BY MAX(SCAN) ASC
You could encapsulate this within a subquery if you don't want to return the [Row] column.
you can user row_number to get top 1 row per customer
In the where clause need to return values with pos value as 1
sample query
row_number() over ( partition by GFCUS order by SAPOD desc) as pos