Need to add a calculated field using T-SQL - tsql

I have a Query that I would like to add a Calculated field to. I need to add Projected Sales for 2013. The calculation would be the current count of months divided by the total year's sales times 12. I have a field for FiscalMonthNum that is not in the query yet. Can someone please show me how I could add the field I need?
SELECT
a.Vendor,
vn.ACNAME AS Vendor_Name,
a.FiscalYear,
a.QtySold,
a.ExtCost
FROM
dbo.S2K_VEND vn
INNER JOIN
(SELECT
sd.IFPRVN AS Vendor,
fc.FiscalYear,
SUM(sd.SBQSHP) AS QtySold,
SUM(sd.SBEPRC) AS ExtCost
FROM
dbo.SalesData sd
LEFT OUTER JOIN dbo.FiscalCalendar fc ON fc.FiscalDate = sd.SBINDT
WHERE
sd.SBTYPE = 'O'
AND
sd.SBINDT > '2011-12-31'
AND
sd.SBCLS NOT IN ('1500')
GROUP BY
sd.IFPRVN,
fc.FiscalYear
)a
ON vn.ACVEND = a.Vendor
GROUP BY
a.Vendor,
vn.ACNAME,
a.FiscalYear,
a.QtySold,
a.ExtCost

Would the following do the trick? Dividing the sales by the maximum month number and then multiplying by 12?
SELECT
a.Vendor,
vn.ACNAME AS Vendor_Name,
a.FiscalYear,
a.QtySold,
a.ExtCost,
a.PredictedQtySold,
a.PredictedExtCost
FROM
dbo.S2K_VEND vn
INNER JOIN
(SELECT
sd.IFPRVN AS Vendor,
fc.FiscalYear,
12 * (SUM(sd.SBQSHP)/MAX(FiscalMonthNumber)) AS PredictedQtySold,
12 * (SUM(sd.SBEPRC)/MAX(FiscalMonthNumber)) AS PredictedExtCost,
SUM(sd.SBQSHP) AS QtySold,
SUM(sd.SBEPRC) AS ExtCost
FROM
dbo.SalesData sd
LEFT OUTER JOIN dbo.FiscalCalendar fc ON fc.FiscalDate = sd.SBINDT
WHERE
sd.SBTYPE = 'O'
AND
sd.SBINDT > '2011-12-31'
AND
sd.SBCLS NOT IN ('1500')
GROUP BY
sd.IFPRVN,
fc.FiscalYear
)a
ON vn.ACVEND = a.Vendor
GROUP BY
a.Vendor,
vn.ACNAME,
a.FiscalYear,
a.QtySold,
a.ExtCost
;

Related

How to calculate values from previous month to current month

I want to calculate this table. Everytime that there is a new participant per month it will add the previous value to current value.
month
no_participant
2021-01
10
2021-02
20
2021-03
5
2021-04
17
Something like this, output
month
no_participant
count
2021-01
10
10
2021-02
20
30
2021-03
5
35
2021-04
17
52
Here's my query: I am using Postgres. Thanks to your help
SELECT (TO_CHAR(CSD.SCHEDULED_START_DATETIME, 'YYYY-MM'))AS MONTH,
COUNT(DISTINCT PARTICIPANT_ID) AS PARTICIPANT
FROM TSUP.COURSE_SCHEDULE_DETAIL AS CSD
INNER JOIN TSUP.COURSE_PARTICIPANT AS CP
ON CSD.COURSE_SCHEDULE_ID = CP.COURSE_SCHEDULE_ID
INNER JOIN(
SELECT
MIN(COALESCE(CSD.RESCHEDULED_START_DATETIME, CSD.SCHEDULED_START_DATETIME)) AS SCHEDULED_START_DATETIME,
MAX(COALESCE(CSD.RESCHEDULED_END_DATETIME, CSD.SCHEDULED_END_DATETIME)) AS SCHEDULED_END_DATETIME,
COUNT(CSD.SCHEDULED_START_DATETIME) AS "COUNT"
FROM TSUP.COURSE_SCHEDULE_DETAIL AS CSD
INNER JOIN (
SELECT CP.PARTICIPANT_ID AS "PARTICIPANT",
MIN(COALESCE(CSD.RESCHEDULED_START_DATETIME, CSD.SCHEDULED_START_DATETIME)) AS SCHEDULED_START_DATETIME,
MAX(COALESCE(CSD.RESCHEDULED_END_DATETIME, CSD.SCHEDULED_END_DATETIME)) AS SCHEDULED_END_DATETIME
FROM TSUP.COURSE_PARTICIPANT AS CP
INNER JOIN TSUP.COURSE_SCHEDULE_DETAIL AS CSD
ON CP.COURSE_SCHEDULE_ID = CSD.COURSE_SCHEDULE_ID
INNER JOIN TSUP.COURSE_SCHEDULE AS CS
ON CSD.ID = CS.ID
INNER JOIN TSUP.COURSE AS C
ON CS.COURSE_ID = C.ID
INNER JOIN TSUP.COURSE_CATEGORY AS CC
ON C.COURSE_CATEGORY_ID = CC.ID
INNER JOIN TSUP.EMPLOYEE AS E
ON CP.PARTICIPANT_ID = E.ID
INNER JOIN TSUP.MEMBER_ROLE AS MR
ON E.MEMBER_ROLE_ID = MR.ID
WHERE C.MANDATORY = 'Yes'
AND MR.ROLE_TYPE = 'Dev'
AND CC.CATEGORY = 'JJ'
GROUP BY CP.PARTICIPANT_ID)
TEMP ON CSD.SCHEDULED_START_DATETIME = TEMP.SCHEDULED_START_DATETIME
GROUP BY CSD.RESCHEDULED_START_DATETIME, CSD.SCHEDULED_START_DATETIME,
CSD.RESCHEDULED_END_DATETIME, CSD.SCHEDULED_END_DATETIME
)
TEMP ON CSD.SCHEDULED_START_DATETIME = TEMP.SCHEDULED_START_DATETIME
GROUP BY MONTH
The query you provided is verbose, and also does not seem to exactly line up with the sample data. I will give the following query based on the sample data shown:
SELECT month, no_participant, SUM(no_participant) OVER (ORDER BY month) AS count
FROM yourTable
ORDER BY month;
The above logic uses SUM() as an analytic function.

Correlated subquery in Postgres

I have a query like below to find the stock details of certain products.The query is working fine but i think it is not efficient and fast enough(DB: postgresql version 11).
There is a CTE "result_set"in this code where i need to find the "quantity of a product ordered"(qty_last_7d_from_oos_date) during the period between out of stock and last 7 days before out of stock date.Same like this i have to find the revenue also.
So what i did is wrote a same subquery two times one outputting the revenue and other the quantity which is not an efficient step.So someone have any suggestions on how to rewrite this and make it an efficient code.
WITH final as
(
SELECT product_id,product_name,item_sku,out_of_stock_at
,out_of_stock_at - INTERVAL '7 days' as previous_7_days
,back_in_stock_at
FROM oos_base
)
SELECT product_id,product_name,item_sku,out_of_stock_at,previous_7_days
,back_in_stock_at
,(SELECT coalesce(sum(i.qty_ordered), 0) AS qty_last_7d_from_oos_date
FROM ol.orders o
LEFT JOIN ol.items i ON i.order_id = o.order_id
LEFT JOIN ol.products p ON p.product_id = i.product_id AND i.store_id = p.store_id
WHERE o.order_state_2 IN('complete','processing')
AND f.product_id=p.product_id
AND o.created_at_order :: DATE BETWEEN f.previous_7_days::DATE AND COALESCE(f.out_of_stock_at::DATE,current_date)
)
,( SELECT coalesce(sum(i.row_amount_minus_discount_order), 0) AS rev_last_7d_from_oos_date
FROM ol.orders o
LEFT JOIN ol.items i ON i.order_id = o.order_id
LEFT JOIN ol.products p ON p.product_id = i.product_id AND i.store_id = p.store_id
WHERE o.order_state_2 IN('complete','processing')
AND f.product_id=p.product_id
AND o.created_at_order :: DATE BETWEEN f.previous_7_days::DATE AND COALESCE(f.out_of_stock_at::DATE,current_date)
)
FROM final f
In the above code the CTE "final" gives you two dates "out_of_stock_at" &
"previous_7_days". I want to find the quantity and revenue of a product based on this 2 dates means between "previous_7_days" & "out_of_stock_at".
Below query will give the quantity and revenue of the products but the period between "previous_7_days" & "out_of_stock_at"from the above CTE.
As of now i have used the below code two times to obtain the information of revenue and quantity.
SELECT coalesce(sum(i.qty_ordered), 0) AS qty ,
coalesce(sum(i.row_amount_minus_discount_order), 0)
FROM ol.orders o
LEFT JOIN ol.items i ON i.order_id = o.order_id
LEFT JOIN ol.products p ON p.product_id = i.product_id AND i.store_id = p.store_id
WHERE o.order_state_2 IN('complete','processing')
AND f.product_id=p.product_id
AND o.created_at_order :: DATE BETWEEN f.previous_7_days::DATE AND COALESCE(f.out_of_stock_at::DATE,current_date)

How do I efficiently select the most recent record for a set of values TSQL?

I have a set of tables each containing related data and I need to select the most recent set of records for each row in the source table. There are millions of rows and I need to do this efficiently and so far im unable to return only the most recent date for a given number.
For example the current result for a given number is:
CampaignName MobileNumber Date
Campaign A 12345678910 12/02/2018 14:50:30
Campaign B 12345678910 05/02/2018 11:35:22
Only the row for Campaign A should be returned.
I'm essentially trying to get the most recent message sent for each mobile number and the campaign data for that message (each message is part of a campaign.
SELECT CC.campaignname,
Co.mobilenumber,
Max(M.msgcreatetime)
FROM [Database].[dbo].[messages] M WITH(nolock)
INNER JOIN dbo.messagecontact MC WITH(nolock)
ON M.msgid = MC.messageid
INNER JOIN dbo.campaigncontact Co WITH(nolock)
ON Co.contactid = MC.contactid
INNER JOIN dbo.campaign CC WITH(nolock)
ON M.campaignid = CC.campaignid
GROUP BY CC.campaignname,
Co.mobilenumber
Use top 1 with ties and order by row_number:
Using top 1 with ties means you will get all the records where the value of the order by expression is the lowest.
Using row_number() over(partition by Co.mobilenumber order by M.msgcreatetime desc) will return 1 for the last date for each Co.mobilenumber, 2 for the second from last etc'.
SELECT TOP 1 WITH TIES
CC.campaignname,
Co.mobilenumber,
M.msgcreatetime
FROM [Database].[dbo].[messages] M WITH(nolock)
INNER JOIN dbo.messagecontact MC WITH(nolock)
ON M.msgid = MC.messageid
INNER JOIN dbo.campaigncontact Co WITH(nolock)
ON Co.contactid = MC.contactid
INNER JOIN dbo.campaign CC WITH(nolock)
ON M.campaignid = CC.campaignid
ORDER BY ROW_NUMBER() OVER(PARTITION BY Co.mobilenumber ORDER BY M.msgcreatetime desc)

TSQL - How do I use SUM in a virtual COLUMN inside a select?

create proc sp_SumVirtual
as
select a.year, sum(b.PriceDay*b.AmmountDays) profit
from vehicles a, rent b
where a.Matriculation = b.Matriculation
GROUP BY a.year
Okay so, with this I got the amount of money EACH car has made, but I need the whole amount. So, is there a way I can make SUM from the virtual table Profit? Because that is all I need..or do you suggest another way?
Use the WITH ROLLUP on your GROUP BY clause:
SELECT
a.year, SUM(b.PriceDay*b.AmmountDays) profit
FROM
dbo.vehicles a
INNER JOIN
dbo.rent b ON a.Matriculation = b.Matriculation
GROUP BY
a.year WITH ROLLUP
This will give you an additional row with NULL as the value of year and the value in the sum column will be the total sum over all grouped rows.
Update: so you want to have the sum for each year, but also another column with the total sum over all rows of all years??
Try this:
SELECT
a.year,
SUM(b.PriceDay*b.AmmountDays) profit,
(SELECT SUM(b2.PriceDay * b2.AmountDays)
FROM dbo.vehicles a2
INNER JOIN dbo.rent b2 ON a2.Matriculation = b2.Matriculation) AS TotalProfit
FROM
dbo.vehicles a
INNER JOIN
dbo.rent b ON a.Matriculation = b.Matriculation
GROUP BY
a.year
HOWEVER: this will NOT be performing very well, since you calculate the TotalProfit again and again - for each row that will be output.....
Select v.year, Sum(r.PriceDay*r.AmmountDays) profit
From vehicles v Join rent r
On r.Matriculation = v.Matriculation
Group By v.year
With RollUp
You could use a temp table along with UNION ALL:
SELECT
a.year, SUM(b.PriceDay*b.AmmountDays) profit
INTO #Temp
FROM
dbo.vehicles a
INNER JOIN
dbo.rent b ON a.Matriculation = b.Matriculation
GROUP BY
a.year
SELECT *
FROM #Temp
UNION ALL
SELECT year, Sum(profit)
FROM #Temp
Group by year

TOP N problem with GROUP BY clause

The problem: I need to find all active [GiftPledges] that have the last three [GiftDetails] have a zero amount.
SELECT gp.PledgeId FROM GiftPledge gp
INNER JOIN GiftDetail gd ON gp.PledgeId = gd.PledgeId
WHERE gp.PledgeStatus = 'A'
GROUP BY PledgeId
HAVING COUNT(PledgeId) >= 3
Now, I have all my [GiftPledges] that have at least three [GiftDetails].
SELECT TOP 3 gdi.Amt FROM GiftDetail gdi
INNER JOIN GiftHeader ghi ON gdi.GiftRef = ghi.GiftRef
WHERE gdi.PledgeId = gp.PledgeId
ORDER BY ghi.GDate DESC
This gives me the three most recent [GiftDetails] associated with a given [GiftPledge]. The problem is that I don't know how to sum the second query and have it be a part of the WHERE clause in the first query.
I found this article about "Top n per Group" and that seems like the direction I need to be headed, but I'm not sure I'm on the right track.
Any help, clarifications or suggestions would be greatly appreciated.
SELECT gp.PledgeId FROM GiftPledge gp
INNER JOIN GiftDetail gd ON gp.PledgeId = gd.PledgeId
WHERE gp.PledgeStatus = 'A'
GROUP BY PledgeId
HAVING COUNT(PledgeId) >= 3
AND
GP.PledgeID in (
SELECT PledgeID From
(
SELECT TOP 3 gp.PledgeID, gdi.Amt FROM GiftDetail gdi
INNER JOIN GiftHeader ghi ON gdi.GiftRef = ghi.GiftRef
WHERE gdi.PledgeId = gp.PledgeId
ORDER BY ghi.GDate DESC
) x_amt
Group By PledgeID
Having SUM(AMT) ) x_sum = 0
something like that anyway.