Subselect on date - sql

In an Access database there are two tables.
Table one containing Articles and table two contains Prices.
So Articles is the description of all articles and the prices
table just contains an article number, a date date and a price.
If a prices changes, there will be added a new row to prices.
The prices have a date from which on that price shall be used.
Now I want to get the prices that were valid on 01. Oct 2012.
I used my query on current prices and added and prsdat<#02/10/2012#
to the subselect in the query.
Here is what I already have:
SELECT
Articles.ARTNR,
Articles.TXT,
Articles.ACTIVE,
Prices.PRICE,
Prices.PRSGR,
Prices.PRSDAT
FROM
Articles INNER JOIN Prices ON Articles.ARTNR = Prices.ARTNR
WHERE
(((Articles.ACTIVE)="Y") AND
((Prices.PRSGR)=0) AND
((Prices.PRSDAT)=
(SELECT
max(prsdat)
FROM
Prices as art
WHERE
art.artnr = Prices.artnr and prsdat<#02/10/2012#)))
ORDER BY
Articles.ARTNR;
Now the select returns articles that I did not see with this select
I used before, having just added and prsdat<#01/10/2012#.
The result is now 430 articles, before I just had about 260.
The prices returned are older, but I'm not sure about the date format.
In the table I see DD.MM.YYYY, and in the query i shall use MM/DD/YYYY or DD/MM/YYYY?
What is the correct form of this select?

SELECT
a.ARTNR
, a.TXT
, a.ACTIVE -- dubious, since it is constant
, p.PRICE
, p.PRSGR -- dubious, since it is constant
, p.PRSDAT
FROM Articles a
INNER JOIN Prices p ON a.ARTNR = p.ARTNR
WHERE a.ACTIVE = 'Y'
AND p.PRSGR = 0
AND p.prsdat < #02/10/2012#
AND NOT EXISTS (
SELECT *
FROM Prices nx
WHERE nx.ARTNR = p.ARTNR
AND nx.PRSGR = 0
AND nx.prsdat < #02/10/2012#
AND nx.prsdat > p.prsdat
)
ORDER BY
Articles.ARTNR
;

Related

Use query result

I´m having issues with the following query. I have two tables; Table Orderheader and table Bought. The first query I execute gives me, for example, two dates. Based on these two dates, I need to find Production data AND, based on the production data, I need to find the Bought data, and combine those data together. Lets say I do the following:
Select Lotdate From Orderheader where orhsysid = 1
This results in two rows: '2019-02-05' and '2019-02-04'. Now I need to do two things: I need two run two queries using this result set. The first one is easy; use the dates returned and get a sum of column A like this:
Select date, SUM(Amount) from Orderheader where date = Sales.date() [use the two dates here]
The second one is slighty more complicated, I need to find the last day where something has been bought based on the two dates. Production is everyday so Productiondate=Sales.date()-1. But Bought is derived from Productionday and is not everyday so for every Productionday it needs to find the last Boughtday. So I can't say where date = Orderheader.date. I need to do something like:
Select date, SUM(Amount)
FROM Bought
WHERE date = (
SELECT top 1 date
FROM Bought
WHERE date < Orderheader.date)
But twice, for both the dates I got.
This needs to result in 1 table giving me:
Bought.date, Bought.SUM(AMOUNT), Orderheader.date, Orderheader.SUM(AMOUNT)
All based on the, possible multiple, Lotdate(s) I got from the first query from Sales table.
I've been struggling with this for a moment now, using joins and nested queries but I can't seem to figure it out!
Example sample:
SELECT CONVERT(date,ORF.orfDate) as Productiedatum, SUM(orlQuantityRegistered) as 'Aantal'
FROM OrderHeader ORH
LEFT JOIN OrderFrame ORF ON ORH.orhFrameSysID = ORF.orfSysID
LEFT JOIN OrderLine ORL ON ORL.orhSysID = ORH.orhSysID
LEFT JOIN Item ON Item.itmSysID = ORL.orlitmSysID
where CONVERT(date,ORF.orfDate) IN
(
SELECT DISTINCT(CONVERT(date, Lot.lotproductiondate)) as Productiedatum
FROM OrderHeader ORH
LEFT JOIN Registration reg ON reg.regorhSysID = ORH.orhSysID
LEFT JOIN StockRegistration stcreg ON stcreg.stcregRegistrationSysID = reg.regSysID
LEFT JOIN Lot ON Lot.lotSysID = stcregSrclotSysID
WHERE ORH.orhSysID = 514955
AND regRevokeRegSysID IS NULL
AND stcregSrcitmSysID = 5103
)
AND ORL.orlitmSysID = 5103
AND orldirSysID = 2
AND NOT orlQuantityRegistered IS NULL
GROUP BY Orf.orfDate
Sample output:
Productiedatum Aantal
2019-02-05 20
2019-02-06 20
Here I used a nested subquery to get the results from 'Production' (orderheader) because I just can use date = date. I'm struggling with the Sales part where I need to find the last date(s) and use those dates in the Sales table to get the sum of that date.
Expected output:
Productiedatum Aantal Boughtdate Aantal
2019-02-04 20 2019-02-01 55
2019-02-05 20 2019-02-04 60
Try this.
IF OBJECT_ID('tempdb..#Production') IS NOT NULL DROP TABLE #Production
IF OBJECT_ID('tempdb..#Bought') IS NOT NULL DROP TABLE #Bought
CREATE table #Production(R_NO int,ProductionDate datetime,ProductionAmount float)
CREATE table #Bought(R_NO int,Boughtdate datetime,Boughtamount float)
insert into #Production(ProductionDate,ProductionAmount,R_NO)
select p.date ProductionDate,sum(Amount) ProductionAmount,row_number()over (order by p.date) R_NO
from Production P
join Sales s on p.date=S.date-1
where orhsysid=1
group by p.date
declare #loop int,#ProdDate datetime
select #loop =max(R_NO) from #Production
while (1<=#loop)
begin
select #ProdDate=ProductionDate from #Production where r_no=#loop
insert into #Bought(Boughtdate,Boughtamount,R_NO)
select Date,Sum(Amount),#loop R_NO from Bought where date=(
select max(date) from bought B
where B.Date<#ProdDate)
group by Date
set #loop=#loop-1
end
select ProductionDate,ProductionAmount,Boughtdate,Boughtamount from #Bought B
join #Production p on B.R_NO=P.R_NO

Conditional left join on max date and where clause in second table

I am attempting to join a customer table with sales table where I show the list of all customers in database and any paid sale the customer might have in the sales tables. Now a customer can have multiple sales rows in the sales table.
This is an example sales record of one customer with multiple sales in the sale tables
while extracting this record I would like to get only the MAX (q_saledatetime) WHERE the q_paidamount is > 0.
as in show me the last time this customer made a payment to us. So in this case row 2 where they paid 8.90 is what I would like to get for that customer. If a customer has no record in the sales table, show their name/details on the list either way.
My failure at the moment is how to include the where clause of the paid amount + max date column.
ATTEMPT A
select DISTINCT ON (q_customer.q_code)
q_customer.q_code, q_customer.q_name, -- customer info
MAX(q_saleheader.q_saledatetime) AS latestDate, q_saleheader.q_paidamount -- saleheader info
FROM q_customer
LEFT JOIN q_saleheader ON (q_customer.q_code = q_saleheader.q_customercode)
group by q_customer.q_code, q_customer.q_name , q_saleheader.q_saledatetime, q_saleheader.q_paidamount
order by q_customer.q_code ASC
which results in
so for Fred Blogg is picking up details from row 4 instead of 2 (first image). As there's no rule for q_paidamount at this point
ATTEMPT B
SELECT
customer.q_code, customer.q_name, -- customer info
sale.q_saledatetime, sale.q_paidamount -- sale info
FROM q_customer customer
LEFT JOIN (SELECT * FROM q_saleheader WHERE q_saledatetime =
(SELECT MAX(q_saledatetime) FROM q_saleheader b1 where q_paidamount > 0 ))
sale ON sale.q_customercode = customer.q_code
which results in
This doesnt seem to be getting any information from the sale table at all.
Update:
After having a closer look at my first attempt I amended the statement and came up with this solution which achieves the same results as Michal's answer. I just curious to know is there any pitfalls or perfomance disadvantages with the following way.
select DISTINCT ON (q_customer.q_code)
q_customer.q_code, q_customer.q_name, -- customer info
q_saleheader.q_saledatetime, q_saleheader.q_paidamount -- saleheader info
FROM q_customer
LEFT JOIN q_saleheader ON (q_customer.q_code = q_saleheader.q_customercode AND
q_saleheader.q_paidamount > 0 )
group by q_customer.q_code, q_customer.q_name , q_saleheader.q_saledatetime,
q_saleheader.q_paidamount
order by q_customer.q_code ASC, q_saleheader.q_saledatetime DESC
main change was adding AND q_saleheader.q_paidamount > 0 on the join and q_saleheader.q_saledatetime DESC to make sure are getting the top row of that related data. As mentioned both Michal's answer and this solution achieve the same results. Just curious about pitfalls in either of the two ways.
Try this query:
SELECT c.q_code,
c.q_name,
CASE WHEN q_saledatetime <> '1900-01-01 00:00:00.000' THEN q_saledatetime END q_saledatetime,
q_paidamount
FROM (
SELECT c.q_code,
c.q_name,
coalesce(s.q_saledatetime, '1900-01-01 00:00:00.000') q_saledatetime, --it will indicate customer with no data
s.q_paidamount,
ROW_NUMBER() OVER (PARTITION BY c.q_code ORDER BY COALESCE(s.q_saledatetime, '1900-01-01') DESC) rn
FROM q_customer c
LEFT JOIN (SELECT q_saledatetime,
q_paidamount
FROM q_saleheader
WHERE q_paidamount > 0) s
ON c.q_code = s.q_customercode
) c WHERE rn = 1

Using a stored procedure in Teradata to build a summarial history table

I am using Terdata SQL Assistant connected to an enterprise DW. I have written the query below to show an inventory of outstanding items as of a specific point in time. The table referenced loads and stores new records as changes are made to their state by load date (and does not delete historical records). The output of my query is 1 row for the specified date. Can I create a stored procedure or recursive query of some sort to build a history of these summary rows (with 1 new row per day)? I have not used such functions in the past; links to pertinent previously answered questions or suggestions on how I could get on the right track in researching other possible solutions are totally fine if applicable; just trying to bridge this gap in my knowledge.
SELECT
'2017-10-02' as Dt
,COUNT(DISTINCT A.RECORD_NBR) as Pending_Records
,SUM(A.PAY_AMT) AS Total_Pending_Payments
FROM DB.RECORD_HISTORY A
INNER JOIN
(SELECT MAX(LOAD_DT) AS LOAD_DT
,RECORD_NBR
FROM DB.RECORD_HISTORY
WHERE LOAD_DT <= '2017-10-02'
GROUP BY RECORD_NBR
) B
ON A.RECORD_NBR = B.RECORD_NBR
AND A.LOAD_DT = B.LOAD_DT
WHERE
A.RECORD_ORDER =1 AND Final_DT Is Null
GROUP BY Dt
ORDER BY 1 desc
Here is my interpretation of your query:
For the most recent load_dt (up until 2017-10-02) for record_order #1,
return
1) the number of different pending records
2) the total amount of pending payments
Is this correct? If you're looking for this info, but one row for each "Load_Dt", you just need to remove that INNER JOIN:
SELECT
load_Dt,
COUNT(DISTINCT record_nbr) AS Pending_Records,
SUM(pay_amt) AS Total_Pending_Payments
FROM DB.record_history
WHERE record_order = 1
AND final_Dt IS NULL
GROUP BY load_Dt
ORDER BY 1 DESC
If you want to get the summary info per record_order, just add record_order as a grouping column:
SELECT
load_Dt,
record_order,
COUNT(DISTINCT record_nbr) AS Pending_Records,
SUM(pay_amt) AS Total_Pending_Payments
FROM DB.record_history
WHERE final_Dt IS NULL
GROUP BY load_Dt, record_order
ORDER BY 1,2 DESC
If you want to get one row per day (if there are calendar days with no corresponding "load_dt" days), then you can SELECT from the sys_calendar.calendar view and LEFT JOIN the query above on the "load_dt" field:
SELECT cal.calendar_date, src.Pending_Records, src.Total_Pending_Payments
FROM sys_calendar.calendar cal
LEFT JOIN (
SELECT
load_Dt,
COUNT(DISTINCT record_nbr) AS Pending_Records,
SUM(pay_amt) AS Total_Pending_Payments
FROM DB.record_history
WHERE record_order = 1
AND final_Dt IS NULL
GROUP BY load_Dt
) src ON cal.calendar_date = src.load_Dt
WHERE cal.calendar_date BETWEEN <start_date> AND <end_date>
ORDER BY 1 DESC
I don't have access to a TD system, so you may get syntax errors. Let me know if that works or you're looking for something else.

Selecting average total where an associated table has id present

I'm fairly new to SQL and I'm trying to answer this question:
What is the average order total, where product X is present.
We have an orders table, and line items. An order has many line items, which again store the product_id.
SELECT
avg(total)
FROM
orders
WHERE
(shipment_state = 'shipped')
AND (delivery_date BETWEEN '2017-09-11' AND '2017-09-18');
is what I have now and that is working, however I do not know how to fetch and calculate it based on another table (in this case line_item)
You can use exists:
SELECT AVG(o.total)
FROM orders o
WHERE o.shipment_state = 'shipped' AND
o.delivery_date BETWEEN '2017-09-11' AND '2017-09-18' AND
EXISTS (SELECT 1
FROM orderlines ol
WHERE ol.order_id = o.order_id AND
ol.product_id = X
);
Notes:
When you have more than one table in a query, always use table aliases and qualified column names.
When working with dates, BETWEEN is not recommended. The recommended construct is o.delivery_date >= '2017-09-11' AND o.delivery_date < '2017-09-19'. This works for both dates and date/time values.

Unpivot date columns to a single column of a complex query in Oracle

Hi guys, I am stuck with a stubborn problem which I am unable to solve. Am trying to compile a report wherein all the dates coming from different tables would need to come into a single date field in the report. Ofcourse, the max or the most recent date from all these date columns needs to be added to the single date column for the report. I have multiple users of multiple branches/courses for whom the report would be generated.
There are multiple blogs and the latest date w.r.t to the blogtitle needs to be grouped, i.e. max(date_value) from the six date columns should give the greatest or latest date for that blogtitle.
Expected Result:
select u.batch_uid as ext_person_key, u.user_id, cm.batch_uid as ext_crs_key, cm.crs_id, ir.role_id as
insti_role, (CASE when b.JOURNAL_IND = 'N' then
'BLOG' else 'JOURNAL' end) as item_type, gm.title as item_name, gm.disp_title as ITEM_DISP_NAME, be.blog_pk1 as be_blogPk1, bc.blog_entry_pk1 as bc_blog_entry_pk1,bc.pk1,
b.ENTRY_mod_DATE as b_ENTRY_mod_DATE ,b.CMT_mod_DATE as BlogCmtModDate, be.CMT_mod_DATE as be_cmnt_mod_Date,
b.UPDATE_DATE as BlogUpDate, be.UPDATE_DATE as be_UPDATE_DATE,
bc.creation_date as bc_creation_date,
be.CREATOR_USER_ID as be_CREATOR_USER_ID , bc.creator_user_id as bc_creator_user_id,
b.TITLE as BlogTitle, be.TITLE as be_TITLE,
be.DESCRIPTION as be_DESCRIPTION, bc.DESCRIPTION as bc_DESCRIPTION
FROM users u
INNER JOIN insti_roles ir on u.insti_roles_pk1 = ir.pk1
INNER JOIN crs_users cu ON u.pk1 = cu.users_pk1
INNER JOIN crs_mast cm on cu.crsmast_pk1 = cm.pk1
INNER JOIN blogs b on b.crsmast_pk1 = cm.pk1
INNER JOIN blog_entry be on b.pk1=be.blog_pk1 AND be.creator_user_id = cu.pk1
LEFT JOIN blog_CMT bc on be.pk1=bc.blog_entry_pk1 and bc.CREATOR_USER_ID=cu.pk1
JOIN gradeledger_mast gm ON gm.crsmast_pk1 = cm.pk1 and b.grade_handler = gm.linkId
WHERE cu.ROLE='S' AND BE.STATUS='2' AND B.ALLOW_GRADING='Y' AND u.row_status='0'
AND u.available_ind ='Y' and cm.row_status='0' and and u.batch_uid='userA_157'
I am getting a resultset for the above query with multiple date columns which I want > > to input into a single columnn. The dates have to be the most recent, i.e. max of the dates in the date columns.
I have successfully done the Unpivot by using a view to store the above
resultset and put all the dates in one column. However, I do not
want to use a view or a table to store the resultset and then do
Unipivot simply because I cannot keep creating views for every user
one would query for.
The max(date_value) from the date columns need to be put in one single column. They are as follows:
* 1) b.entry_mod_date, 2) b.cmt_mod_date ,3) be.cmt_mod_date , 4) b.update_Date ,5) be.update_date, 6) bc.creation_date *
Apologies that I could not provide the desc of all the tables and the
fields being used.
Any help to get the above mentioned max of the dates from these
multiple date columns into a single column without using a view or a
table would be greatly appreciated.*
It is not clear what results you want, but the easiest solution is to use greatest().
with t as (
YOURQUERYHERE
)
select t.*,
greatest(entry_mod_date, cmt_mod_date, cmt_mod_date, update_Date,
update_date, bc.creation_date
) as greatestdate
from t;
select <columns>,
case
when greatest (b_ENTRY_mod_DATE) >= greatest (BlogCmtModDate) and greatest(b_ENTRY_mod_DATE) >= greatest(BlogUpDate)
then greatest( b_ENTRY_mod_DATE )
--<same implementation to compare each time BlogCmtModDate and BlogUpDate separately to get the greatest then 'date'>
,<columns>
FROM table
<rest of the query>
UNION ALL
Select <columns>,
case
when greatest (be_cmnt_mod_Date) >= greatest (be_UPDATE_DATE)
then greatest( be_cmnt_mod_Date )
when greatest (be_UPDATE_DATE) >= greatest (be_cmnt_mod_Date)
then greatest( be_UPDATE_DATE )
,<columns>
FROM table
<rest of the query>
UNION ALL
Select <columns>,
GREATEST(bc_creation_date)
,<columns>
FROM table
<rest of the query>