Calculating the minimum of a rolling minimum grouped by another column value - sql

I am writing a procedure to calculate a 6 month rolling minimum that also takes the lowest rolling minimum from each facility. The code below is what I've written so far, but the problem is that it tells me F.normalized_facility_id is a column that doesnt exist even though it very much does. Im thinking it has something to do with my joins and sub query, but I cannot understand how to make it recognize those column names. Please let me know if more info is needed to complete this query. I appreciate any feedback!
SELECT
min(F.rollmin) as 'minmin',
F.normalized_facility_id
FROM
(
SELECT SR.report_id
, SR.period_id
, Min(SR.benzene_concentration)
Over(order by F.normalized_facility_id
ROWS BETWEEN 11 preceding
and current ROW ) as rollmin
FROM PassiveBenzene.sampler_results SR
INNER
JOIN PassiveBenzene.report R
ON R.report_id = SR.report_id
INNER
JOIN PassiveBenzene.facility F
ON F.facility_id = R.facility_id
) F
GROUP BY F.normalized_facility_id
ORDER BY minmin

Related

SQL - sum column for every date

This seemed like a very easy thing to do but I got stuck. I have a query like this:
select op.date, count(p.numberofoutstanding)
from people p
left join outstandingpunches op
on p.fullname = op.fullname
group by op.date
That outputs a table like this:
How can I sum over the dates so the sum for each row is equal to the sums up to that date? For example, the first column would be 27, the second would be 27 + 4, the third 27 + 4 + 11, etc.
I encountered this and this question, and I saw people are using OVER in their queries for this, but I'm confused by what do I have to partition. I tried partitioning by date but it's giving me incorrect results.
You can use a cumulative sum. This looks like:
select op.date, count(*),
sum(count(*)) over (order by op.date) as running_count
from people p join
outstandingpunches op
on p.fullname = op.fullname
group by op.date;
Note: I changed the join from a left join to an inner join. You are aggregating by a column in the second table. Your results have no examples of a NULL date column and that doesn't seem useful. Hence, it seems that rows are assumed to match.
I believe you need to use sum and not count.
select o.date_c,
sum(sum(p.numberofoutstanding)) over (order by o.date_c)
from people p
left join outstandingpunches o on p.fullname = o.fullname
group by o.date_c;
Here is a small demo:
DEMO
Have in mind that I have renamed your column date to date_c. I believe you should not use data types as column names.

Transposing and summing the top 5 results in Teradata SQL Assistant

I have a query that I converted from Access and is currently working correctly in Teradata SQL Assistant. The data pulled is just a standard table full of all of the data I need.
What I am wondering is: Can something be added to this query that will essentially sum up all of the Exposure values and then only show the top 5 Divisions by greatest to smallest sum (of those Top 5). Also, transposing the data so that my Topics are the left most column.
Here is the working code, details omitted.
SELECT
A.AS_OF_DT
, B.DIVISION
, B.CLASS
, Sum(A.BALANCE/1000000) AS "Bal in MMs"
, Sum(A.EXPOSURE/1000000) AS "Exp in MMs"
, Sum(CASE WHEN A.STATUS = 'NACC' THEN (B.BALANCE/1000000) ELSE 0 END) AS "NPL Bal as MMs"
FROM DB.TABLE1 A LEFT JOIN DB.TABLE2 B ON A.NAICS = B.NAICS_CD
WHERE A.AS_OF_DT= '2017-03-31'
GROUP BY
A.AS_OF_DT,
B.DIVISION,
B.CLASS
ORDER BY SUM (A.EXPOSURE/1000000) DESC
Essentially I want the columns to be the following:
DIVISION|DATE|
Below DIVISION would only be the Top 5 DIVISIONS summarized by EXPOSURE (under DATE)
I can try and clarify if needed. Just let me know.
Thanks!
End result is to have a datapaste I can throw into Excel without the manual work of transposing the data in Excel along with writing formulas to rummage through the 1000's of results of the base query to find summarize the individual Divisions and then picking the top 5 each month.
Thanks!
Shill
To get the 5 top for each division, you can use QUALIFY.
Add this to the end of you query:
QUALIFY ROW_NUMBER() over (PARTITION BY AS_OF_DATE,DIVISION order by (SUM (A.EXPOSURE/1000000))
For your other questions, SQL Assistant isn't much of a presentation tool, it won't do what you are asking for.
If your query already work,
try replacing:
SELECT
By:
SELECT top 10
(line 1)

How to calculate portfolio performance in Access

I've found this question particularly hard to google as the search terms come up with matching results, but not what I'm looking for...
I am trying to calculate the performance of a stock over a given time period using MS Access.
Example Calculation:
01.01.2016 Price: 100.00
25.02.2016 Price: 110.00
Pseudo Code:
Performance = Ending Price/Starting Price - 1
As simple as this would be to calculate in Excel, I can't seem to get it done in MS Access. My attempt thus far already fails on the simple task to get the end date. The Failure message is:
"You tried to execute a query that does not include the specified
expression'MoPo_BM_ID'as part of an aggregate function"
UPDATE:
I found a website that included some code that creates the desired result. The example works fine, but I tried adapting it to my own situation but am getting the error message "At most one record can be returned by this subquery".
SELECT x.Mandat_ID, x.BeginPrice, x.EndPrice, ([EndPrice]-[BeginPrice])/[BeginPrice] AS RETURN
FROM (SELECT Mandat_ID,
(SELECT Value AS BeginDate
FROM tbl_AMSDB_IndexMFP AS P
WHERE (Mandat_ID = Mandat_ID)
AND (Date =
(SELECT MIN(Date) AS Expr1
FROM tbl_AMSDB_IndexMFP AS D
WHERE (Mandat_ID = Mandat_ID)))) AS BeginPrice,
(SELECT Value AS BeginDate
FROM tbl_AMSDB_IndexMFP AS P
WHERE (Mandat_ID = Mandat_ID)
AND (Date =
(SELECT MAX(Date) AS Expr1
FROM tbl_AMSDB_IndexMFP AS D
WHERE (Mandat_ID = Mandat_ID)))) AS EndPrice
FROM tbl_AMSDB_IndexMFP
GROUP BY Mandat_ID) AS x
WHERE Mandat_ID=6028;
How can I get it to show me one record?
To get the max date to work, you need to group by the other fields in the select. So your query becomes
SELECT
tbl_MoPo_BM.MoPo_BM_ID,
tbl_AMSDB_IndexMFP.Mandat_ID,tbl_MoPo_BM.Launch_Date,
Max([tbl_AMSDB_IndexMFP]![Date]) AS End_Date
FROM
tbl_AMSDB_IndexMFP
INNER JOIN tbl_MoPo_BM ON tbl_AMSDB_IndexMFP.Mandat_ID =
tbl_MoPo_BM.AMSDB_MoPo_Code
GROUP BY
tbl_MoPo_BM.MoPo_BM_ID,
tbl_AMSDB_IndexMFP.Mandat_ID,
tbl_MoPo_BM.Launch_Date,
WHERE (((tbl_MoPo_BM.MoPo_BM_ID)=107))
Without knowing what your value/price field(s) are, whether the Launch_Date is the start date and whether duplicate entries are in your indexMFP table I can't write the rest to give you the answer to your Pseudo Performance calculation.

Explanation for SQL that finds difference in times between current and previous rows

I'm new to SQL, and while I've learned how to do the basics, I'm still not familiar with some of the more complex functions. I recently discovered this snippet of code from a different question on here that does exactly what I need (finding the difference in times between the current and previous rows), but I don't understand exactly how it works. I hate just blindly copying-and-pasting, and I might have to adapt this for something in the future. Anybody willing to explain how this query is doing what it's doing (with emphasis on the SELECT FROM JOIN ON business at the bottom)?
WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY UpdateTime) AS rn
FROM myTable
)
SELECT DATEDIFF(second, mc.UpdateTime, mp.UpdateTime)
FROM rows mc
JOIN rows mp
ON mc.rn = mp.rn - 1
SELECT *, ROW_NUMBER() OVER (ORDER BY UpdateTime) AS rn
FROM myTable
means select all columns from myTable, and add column rn which will contain row number and all rows must be sorted by UpdateTime column.
Now, basically,
FROM rows mc
JOIN rows mp
ON mc.rn = mp.rn - 1
means take rows with alias mc (m current) and join it with rows (same rowset) with alias mp (m previous) where mc.rn equals to mp.rn - 1.
The rest is obvious I guess?
The important part is actually the WITH block, which extends the existing table information with a new column that just numbers the rows continuously.
The JOIN in the SELECT statement makes sure that only row X and X-1 are compared. For each row in rows SQL Server takes also the previous row and adds the timestamp difference in seconds to the result set.

SQL conundrum, how to select latest date for part, but only 1 row per part (unique)

I am trying to wrap my head around this one this morning.
I am trying to show inventory status for parts (for our products) and this query only becomes complex if I try to return all parts.
Let me lay it out:
single table inventoryReport
I have a distinct list of X parts I wish to display, the result of which must be X # of rows (1 row per part showing latest inventory entry).
table is made up of dated entries of inventory changes (so I only need the LATEST date entry per part).
all data contained in this single table, so no joins necessary.
Currently for 1 single part, it is fairly simple and I can accomplish this by doing the following sql (to give you some idea):
SELECT TOP (1) ldDate, ptProdLine, inPart, inSite, inAbc, ptUm, inQtyOh + inQtyNonet AS in_qty_oh, inQtyAvail, inQtyNonet, ldCustConsignQty, inSuppConsignQty
FROM inventoryReport
WHERE (ldPart = 'ABC123')
ORDER BY ldDate DESC
that gets me my TOP 1 row, so simple per part, however I need to show all X (lets say 30 parts). So I need 30 rows, with that result. Of course the simple solution would be to loop X# of sql calls in my code (but it would be costly) and that would suffice, but for this purpose I would love to work this SQL some more to reduce the x# calls back to the db (if not needed) down to just 1 query.
From what I can see here I need to keep track of the latest date per item somehow while looking for my result set.
I would ultimately do a
WHERE ldPart in ('ABC123', 'BFD21', 'AA123', etc)
to limit the parts I need. Hopefully I made my question clear enough. Let me know if you have an idea. I cannot do a DISTINCT as the rows are not the same, the date needs to be the latest, and I need a maximum of X rows.
Thoughts? I'm stuck...
SELECT *
FROM (SELECT i.*,
ROW_NUMBER() OVER(PARTITION BY ldPart ORDER BY ldDate DESC) r
FROM inventoryReport i
WHERE ldPart in ('ABC123', 'BFD21', 'AA123', etc)
)
WHERE r = 1
EDIT: Be sure to test the performance of each solution. As pointed out in this question, the CTE method may outperform using ROW_NUMBER.
;with cteMaxDate as (
select ldPart, max(ldDate) as MaxDate
from inventoryReport
group by ldPart
)
SELECT md.MaxDate, ir.ptProdLine, ir.inPart, ir.inSite, ir.inAbc, ir.ptUm, ir.inQtyOh + ir.inQtyNonet AS in_qty_oh, ir.inQtyAvail, ir.inQtyNonet, ir.ldCustConsignQty, ir.inSuppConsignQty
FROM cteMaxDate md
INNER JOIN inventoryReport ir
on md.ldPart = ir.ldPart
and md.MaxDate = ir.ldDate
You need to join into a Sub-query:
SELECT i.ldPart, x.LastDate, i.inAbc
FROM inventoryReport i
INNER JOIN (Select ldPart, Max(ldDate) As LastDate FROM inventoryReport GROUP BY ldPart) x
on i.ldPart = x.ldPart and i.ldDate = x.LastDate