How to calculate the average monthly consumption sales in sql server 2008 - sql-server-2008

How to calculate the average monthly consumption sales in sql server 2008
SELECT * FROM (SELECT year(OrderDate) as [year],left(datename(month,OrderDate),3)as [month],Qty as QTY FROM DailyDispatch where CustID=1 ) as s PIVOT ( SUM(QTY)FOR [month] IN (jan, feb, mar, apr,may, jun, jul, aug, sep, oct, nov, dec))as P
i am getting the result,but i want to do the sum of all months and dividing it to the current month.
for eg the all sum of sales up-to this September is 1000,so i want to 1000/9 and display the result.

You didn't mention much about your data, but you could do the following from what I understood:
-- Declare Table Varibale
DECLARE #DailyDispatch TABLE (OrderDate DATETIME, Qty INT, CustID INT)
-- Insert some test records
INSERT INTO #DailyDispatch VALUES (GETDATE()+ 90, 12000, 1),(GETDATE()+60, 11000, 1), (GETDATE()+30, 10000, 1), (GETDATE(), 9000, 1)
,(GETDATE()-30, 8000, 1), (GETDATE()-60, 7000, 1), (GETDATE()-90, 6000, 1),(GETDATE()-120, 5000, 1)
,(GETDATE()-150, 4000, 1), (GETDATE()-180, 3000, 1), (GETDATE()-210, 2000, 1),(GETDATE()-240, 1000, 1)
-- Finally, the SQL:
SELECT *
FROM (
SELECT year(OrderDate) AS [year]
,left(datename(month, OrderDate), 3) AS [month]
,Qty / DATEPART(m, OrderDate) AS QTY
FROM #DailyDispatch
WHERE CustID = 1
) AS s
PIVOT(SUM(Qty) FOR [month] IN (
jan
,feb
,mar
,apr
,may
,jun
,jul
,aug
,sep
,oct
,nov
,dec
)) AS P
It would help others to answer your question if you had include some test data (with the help of table variables, for example) in your question, so others wouldn't have to spend time on the dataset to help you out. Hope this helps.

Related

Calculating product purchases in a Financial Year | SQL Server

I would like to find out product purchases for 2 financial years (FY16-17 & FY17-18).
To go about it:
OwnerID: 101, the first purchase is in 2014 with 3 purchases in FY17-18.
OwnerID: 102, the first purchase is in 2011 with 1 purchase in FY16-17, 1 purchase in FY17-18.
OwnerID: 103, the first purchase is in 2017 however should not be considered as he's a new customer with only 1 purchase in FY17-18. (i.e. first purchase not considered if new customer)
OwnerID: 104, the first purchase is in 2016 but made 3 more purchases in FY16-17.
Code:
CREATE TABLE Test
(
OwnerID INT,
ProductID VARCHAR(255),
PurchaseDate DATE
);
INSERT INTO Test (OwnerID, ProductID, PurchaseDate)
VALUES (101, 'P2', '2014-04-03'), (101, 'P9', '2017-08-09'),
(101, 'P11', '2017-10-05'), (101, 'P12', '2018-01-15'),
(102, 'P1', '2011-06-02'), (102, 'P3', '2016-06-03'),
(102, 'P10', '2017-09-01'),
(103, 'P8', '2017-06-23'),
(104, 'P4', '2016-12-17'), (104, 'P5', '2016-12-18'),
(104, 'P6', '2016-12-19'), (104, 'P7', '2016-12-20');
Desired output:
FY16-17 FY17-18
-----------------
5 4
I tried the below query to fetch records that aren't first occurrence and there by fetching the count within financial years:
SELECT *
FROM
(SELECT
ROW_NUMBER() OVER(PARTITION BY OwnerID ORDER BY PurchaseDate) AS OCCURANCE
FROM Test
GROUP BY OwnerID, PurchaseDate)
WHERE
OCCURANCE <> 1
However it throws an error:
Msg 102, Level 15, State 1, Line 5
Incorrect syntax near ')'.
The subquery needs to have an alias - try this:
SELECT *
FROM
(SELECT
ROW_NUMBER() OVER(PARTITION BY OwnerID ORDER BY PurchaseDate) AS OCCURRENCE
FROM Test
GROUP BY OwnerID, PurchaseDate) subQry
WHERE
subQry.OCCURRENCE <> 1
I am using IIF to separate the two fiscal years and subquery to filter out those with only one purchase
SELECT SUM(IIF(PurchaseDate >= '2016-04-01' AND PurchaseDate < '2017-04-01',1,0)) AS 'FY16-17',
SUM(IIF(PurchaseDate >= '2017-04-01' AND PurchaseDate < '2018-04-01',1,0)) AS 'FY17-18'
FROM test t1
JOIN (SELECT ownerID, COUNT(*) count
FROM test
GROUP BY ownerID) t2 on t1.ownerID = t2.ownerID
WHERE t2.count > 1

SQL: How to find min value per group in sql?

I have the following table snapshots:
domain year month day
--- --- --- ---
google 2007 04 15
google 2005 08 31
google 2005 12 01
facebook 2006 04 15
facebook 2006 02 25
facebook 2008 01 01
What I want to retrieve is the first (earliest) date of each domain.
So the output should be:
google 2005 08 31
facebook 2006 02 25
I have tried the following query, but it retrieves the minimum value for each column:
select domain, min(year), min(month), min(day) from snapshots group by domain
As mentioned you should use concatenation to create a single date and then select the lowest value.
select domain, MIN(CAST(CONCAT(`year`, '-'`,month`,'-',`day`) AS DATE)) from snapshots group by domain
Haven't tested this but this should give you an idea.
You can concatenate the values from the date field, cast them as date and select the min date (i expect the values to be varchar in this case):
SELECT domain,
MIN(CAST(CONCAT(year,'-',month,'-',day) AS date))
FROM snapshots
GROUP BY domain;
In MySQL:
SELECT
domain,
FROM_UNIXTIME(UNIX_TIMESTAMP(MIN(CONCAT(year,'-',month,'-',day))), '%Y') as y,
FROM_UNIXTIME(UNIX_TIMESTAMP(MIN(CONCAT(year,'-',month,'-',day))), '%m') as m,
FROM_UNIXTIME(UNIX_TIMESTAMP(MIN(CONCAT(year,'-',month,'-',day))), '%d') as d
FROM snapshots
GROUP BY domain;
There might be easier solutions, but you can create a new column of date type from the three columns year, month, and day. Then get the min date as following:
SELECT DISTINCT s.domain, s.year, s.month, s.day
FROM
(
SELECT domain, year,month,day,
STR_TO_DATE(CONCAT(`year`,'-',LPAD(`month`,2,'00'),'-',LPAD(`day`,2,'00')) ,'%Y-%m-%d') AS FullDate
FROM snapshots
) AS s
INNER JOIN
(
SELECT domain, MIN(Fulldate) MinDate
FROM
(
SELECT domain, year,month,day,
STR_TO_DATE(CONCAT(`year`,'-',LPAD(`month`,2,'00'),'-',LPAD(`day`,2,'00')) ,'%Y-%m-%d') AS FullDate
FROM snapshots
) AS t
GROUP BY domain
) AS t ON t.MinDate = s.FullDate
AND t.Domain = s.Domain;
demo
This will give you the exact results that you want:
| domain | year | month | day | MinDate |
|----------|------|-------|-----|------------|
| google | 2005 | 8 | 31 | 2005-08-31 |
| facebook | 2006 | 2 | 25 | 2006-02-25 |
Can you try this please and let me know if it solves your problem without concatenation? Could be made more robust with subqueries if necessary.
CREATE TABLE domainDate(domain CHAR(25), `year` INT, `month` INT, `day` INT);
INSERT INTO domainDate VALUES
('google', 2007, 04, 15),
('google', 2005, 08, 31),
('google', 2005, 12, 01),
('facebook', 2006, 04, 15),
('facebook', 2006, 02, 25),
('facebook', 2008, 01, 01);
SET #VDomain := '';
SELECT domain, `year`, `month`, `day` FROM domainDate HAVING #VDomain != #VDomain := domain ORDER BY domain, `year` * 10000 + `month` * 100 + `day`;
Thanks,
James
You can try ranking function ROW_NUMBER()
CREATE TABLE domainDate(domain CHAR(25), [year] INT, [month] INT, [day] INT);
INSERT INTO domainDate VALUES
('google', 2007, 04, 15),
('google', 2005, 08, 31),
('google', 2005, 12, 01),
('facebook', 2006, 04, 15),
('facebook', 2006, 02, 25),
('facebook', 2008, 01, 01);
SELECT domain
,[year]
,[month]
,[day]
FROM
(
SELECT domain
,[year]
,[month]
,[day]
,ROW_NUMBER() OVER(PARTITION BY domain ORDER BY [year], [month], [day]) AS RN
FROM domainDate
) t
WHERE RN = 1

SQL Server 2008: LAG and runningTotals

CREATE TABLE #NetAmounts
(
priority int,
NetAmount decimal(10, 2),
DedicatedAmt decimal(10, 2)
)
INSERT INTO #NetAmounts (priority, NetAmount, DedicatedAmt)
VALUES (1, 6000, 2500),
(2, 6000, 2500),
(3, 6000, 2500),
(4, 6000, 2500)
Net Amount is always same throughout.
I want to update Dedicated Amount so that the sum of dedicated amount is always equals to the netamount by priority order
Expected Result:
Priority NetAmount DedicatedAmt
---------------------------------
1 6000 2500
2 6000 2500
3 6000 1000
4 6000 0
My query (not working)
;WITH CTE AS
(
SELECT
*,
RunningTotal = SUM(DedicatedAmt) OVER(ORDER BY 1)
FROM #NetAmounts
)
SELECT
Priority,
Netamount,
DedicatedAmt = CASE
WHEN DedicatedAmt > RunningTotal
THEN CASE
WHEN LAG(Netamount, 1, Netamount) OVER(ORDER BY Priority) >= DedicatedAmt
AND RunningTotal <= Netamount
THEN ABS(LAG(Netamount, 1, Netamount) OVER(ORDER BY Priority) - DedicatedAmt)
ELSE 0
END
ELSE DedicatedAmt
END
FROM CTE
Thanks

MYSQL query - getting totals by month

http://sqlfiddle.com/#!2/6a6b1
The scheme is given above.. all I want to do is get the results as the total of sales/month... the user will enter a start date and end date and I can generate (in PHP) all the month and years for those dates. For example, if I want to know the total number of "sales" for 12 months, I know I can run 12 individual queries with start and end dates, but I want to run only one query where the result will look like:
Month numofsale
January - 2
Feb-1
March - 23
Apr - 10
and so on...
or just a list of sales without the months, I can then pair it to the array of months generated in the PHP ...any ideas...
Edit/schema and data pasted from sqlfiddle.com:
CREATE TABLE IF NOT EXISTS `lead_activity2` (
`lead_activity_id` int(11) NOT NULL AUTO_INCREMENT,
`sp_id` int(11) NOT NULL,
`act_date` datetime NOT NULL,
`act_name` varchar(255) NOT NULL,
PRIMARY KEY (`lead_activity_id`),
KEY `act_date` (`act_date`),
KEY `act_name` (`act_name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
INSERT INTO `lead_activity2` (`lead_activity_id`, `sp_id`, `act_date`, `act_name`) VALUES
(1, 5, '2012-10-16 16:05:29', 'sale'),
(2, 5, '2012-10-16 16:05:29', 'search'),
(3, 5, '2012-10-16 16:05:29', 'sale'),
(4, 5, '2012-10-17 16:05:29', 'DNC'),
(5, 5, '2012-10-17 16:05:29', 'sale'),
(6, 5, '2012-09-16 16:05:30', 'SCB'),
(7, 5, '2012-09-16 16:05:30', 'sale'),
(8, 5, '2012-08-16 16:05:30', 'sale'),
(9, 5,'2012-08-16 16:05:30', 'sale'),
(10, 5, '2012-07-16 16:05:30', 'sale');
SELECT DATE_FORMAT(date, "%m-%Y") AS Month, SUM(numofsale)
FROM <table_name>
WHERE <where-cond>
GROUP BY DATE_FORMAT(date, "%m-%Y")
Check following in your fiddle demo it works for me (remove where clause for testing)
SELECT DATE_FORMAT(act_date, "%m-%Y") AS Month, COUNT(*)
FROM lead_activity2
WHERE <where-cond-here> AND act_name='sale'
GROUP BY DATE_FORMAT(act_date, "%m-%Y")
It returns following result
MONTH COUNT(*)
07-2012 1
08-2012 2
09-2012 1
10-2012 3
You can try query as given below
select SUM(`SP_ID`) AS `Total` , DATE_FORMAT(act_date, "%M") AS Month, Month(`ACT_DATE`) AS `Month_number` from `lead_activity2` WHERE `ACT_DATE` BETWEEN '2012-05-01' AND '2012-12-17' group by Month(`ACT_DATE`)
Here 2012-05-01 and 2012-12-17 are date input from form. and It will be return you the sum of sales for particular month if exist in database.
thanks
Try this query -
SELECT
MONTH(act_date) month, COUNT(*)
FROM
lead_activity2
WHERE
YEAR(act_date) = 2012 AND act_name = 'sale'
GROUP BY
month
Check WHERE condition if it is OK for you - act_name = 'sale'.
If you want to output month names, then use MONTHNAME() function instead of MONTH().
SELECT YEAR(act_date), MONTH(act_date), COUNT(*)
FROM lead_activity2
GROUP BY YEAR(act_date), MONTH(act_date)
For getting data by month or any other data based on column you have to add GROUP BY.
You can add many columns or calculated values to GROUP BY.
I assume that "num of sales" means count of rows.
Sometimes you might want the month names as Jan, Feb, Mar .... Dec possibly for a Chart likeFusionChart
SELECT DATE_FORMAT(date, "%M") AS Month, SUM(numofsale)
FROM <Table_name>
GROUP BY DATE_FORMAT(date, "%M")
Results would look like this on table
MONTH COUNT(*)
Jul 1
Aug 2
SEP 1
OCT 3

Group by, with rank and sum - not getting correct output

I'm trying to sum a column with rank function and group by month, my code is
select dbo.UpCase( REPLACE( p.Agent_name,'.',' '))as Agent_name, SUM(convert ( float ,
p.Amount))as amount,
RANK() over( order by SUM(convert ( float ,Amount )) desc ) as arank
from dbo.T_Client_Pc_Reg p
group by p.Agent_name ,p.Sale_status ,MONTH(Reg_date)
having [p].Sale_status='Activated'
Currently I'm getting all total value of that column not month wise
Name amount rank
a 100 1
b 80 2
c 50 3
for a amount 100 is total amount till now but , i want get current month total amount not last months..
Maybe you just need to add a WHERE clause? Here is a minor re-write that I think works generally better. Some setup in tempdb:
USE tempdb;
GO
CREATE TABLE dbo.T_Client_Pc_Reg
(
Agent_name VARCHAR(32),
Amount INT,
Sale_Status VARCHAR(32),
Reg_date DATETIME
);
INSERT dbo.T_Client_Pc_Reg
SELECT 'a', 50, 'Activated', GETDATE()
UNION ALL SELECT 'a', 50, 'Activated', GETDATE()
UNION ALL SELECT 'b', 20, 'Activated', GETDATE()
UNION ALL SELECT 'b', 20, 'Activated', GETDATE()
UNION ALL SELECT 'b', 20, 'Activated', GETDATE()
UNION ALL SELECT 'b', 20, 'Activated', GETDATE()
UNION ALL SELECT 'b', 20, 'NotActivated', GETDATE()
UNION ALL SELECT 'c', 25, 'Activated', GETDATE()
UNION ALL SELECT 'c', 25, 'Activated', GETDATE()
UNION ALL SELECT 'c', 25, 'Activated', GETDATE()-40;
Then the query:
SELECT
Agent_name = UPPER(REPLACE(Agent_name, '.', '')),
Amount = SUM(CONVERT(FLOAT, Amount)),
arank = RANK() OVER (ORDER BY SUM(CONVERT(FLOAT, Amount)) DESC)
FROM dbo.T_Client_Pc_Reg
WHERE Reg_date >= DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP), 0)
AND Reg_date < DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) + 1, 0)
AND Sale_status = 'Activated'
GROUP BY UPPER(REPLACE(Agent_name, '.', ''))
ORDER BY arank;
Now cleanup:
USE tempdb;
GO
DROP TABLE dbo.T_Client_Pc_Reg;