Calculate percentage of revenue per month - sql

I have the following underlying data:
+-------+-------+---------------+
| Order | Month | sqft produced |
+-------+-------+---------------+
| 1001 | 4 | 10.29 |
| 1001 | 6 | 4'367.66 |
| 1001 | 7 | 203.57 |
| 1001 | 8 | 294.61 |
| 1001 | 9 | 92.28 |
| 1001 | 10 | 34.47 |
| 1001 | 12 | 16.59 |
| 1002 | 1 | 1.74 |
| 1002 | 4 | 19.54 |
| 1002 | 7 | 5'552.21 |
| 1002 | 9 | 309.62 |
| 1002 | 10 | 24.15 |
| 1002 | 12 | 52.16 |
| 1003 | 5 | 807.45 |
+-------+-------+---------------+
Those are three orders and I want to split the revenue according to the percentage of sqft produced in each month.
The revenue table:
+-------+-----------+
| Order | Revenue |
+-------+-----------+
| 1001 | 1'135'465 |
| 1002 | 1'773'499 |
| 1003 | 172'633 |
+-------+-----------+
So the output of the query should look like this:
+-------+-------+------------------+
| Order | Month | Revenue produced |
+-------+-------+------------------+
| 1001 | 4 | 2'327.72 |
| 1001 | 6 | 988'017.67 |
| 1001 | 7 | 46'050.00 |
| 1001 | 8 | 66'644.36 |
| 1001 | 9 | 20'874.86 |
| 1001 | 10 | 7'797.53 |
| 1001 | 12 | 3'752.86 |
| 1002 | 1 | 517.82 |
| 1002 | 4 | 5'815.02 |
| 1002 | 7 | 1'652'314.97 |
| 1002 | 9 | 92'141.64 |
| 1002 | 10 | 7'186.94 |
| 1002 | 12 | 15'522.60 |
| 1003 | 5 | 172'633.00 |
+-------+-------+------------------+
I am struggling with a way of getting the underlying data in that format because I can't seem to be able to split it by month.

Getting the percentage via dividing the square footage over the sum of the square footage partitioned over the [Order] would get you what you are looking for:
select p.[Order],
[Month],
Revenue,
[sqft produced],
CAST([sqft produced] / SUM([sqft produced]) OVER(PARTITION BY p.[Order]) AS DECIMAL(10,5)) * 100 as sqft_percentage,
Revenue * CAST([sqft produced] / SUM([sqft produced]) OVER(PARTITION BY p.[Order]) AS DECIMAL(10,5)) as revenue_produced
FROM [Orders] p
INNER JOIN Revenue r
ON r.[Order] = p.[Order]

Let's call the first table sqft and the second revenues. To avoid reserved words, the first table column's names will be:
order_id, month_num, sqft_produced
The second:
order_id, total_revenue
The SQL for what you need goes something like this (this is for Oracle):
SELECT order_id, month_num, (sqft_produced / total_sqft * total_revenue) revenue_produced
FROM sqft INNER JOIN
(SELECT order_id, total_sqft, total_revenue FROM (
(SELECT order_id, sum(sqft_produced) total_sqft
GROUP BY order_id) sqfts INNER JOIN revenues ON sqfts.order_id = revenues.order_id)) totals
ON sqft.order_id = totals.order_id;
Step by step:
SELECT order_id, sum(sqft_produced) total_sqft
GROUP BY order_id;
This gets you total square feet produced by order.
(SELECT order_id, sum(sqft_produced) total_sqft
GROUP BY order_id) sqfts INNER JOIN revenues ON sqfts.order_id = revenues.order_id;
This gets you a table with total revenues and total square feet.
And then you join this table to your sqft table and divide the square feet produced each month by total square feet and multiply by total revenue, thus splitting the revenue proportionally to square feet.

Related

SELECTing monthly order amounts and item subtotals in a single query with two tables

I have an Orders table in the form:
| id | service_fee_cents | grand_total_cents | created_at |
|----|-------------------|-------------------|---------------|
| 1 | 1400 | 10000 | Jan 21 2018 |
| 2 | 1000 | 10000 | Feb 16 2018 |
| 3 | 500 | 10000 | March 21 2018 |
| 4 | 500 | 10000 | March 20 2018 |
And an Items table in the form
| id | order_id | title | price_cents | quantity |
|----|----------|--------|-------------|----------|
| 1 | 1 | lorem | 2000 | 2 |
| 2 | 1 | ipsum | 2030 | 1 |
| 3 | 2 | pie | 4000 | 4 |
| 4 | 3 | cheese | 6000 | 2 |
| 5 | 3 | burger | 7000 | 1 |
| 6 | 4 | custar | 1000 | 1 |
And I'm trying to run a SQL query to get a result in the form
| month | total_service_fee | total_grand_total | total_subtotal |
|-----------|-------------------|-------------------|----------------|
|2017-11-01 | 42 | 1,610 | 610 |
|2017-12-01 | 30 | 19,912 | 1,912 |
|2018-01-01 | 179 | 1,413 | 413 |
|2018-02-01 | 165 | 2,910 | 910 |
|2018-03-01 | 1,403 | 10,727 | 1,727 |
I've managed to get the first three columns using this query:
SELECT
date_trunc('month', created_at)::date AS month,
SUM(service_fee_cents) / 100 AS total_service_fee,
SUM(grand_total_cents) / 100 AS total_grand_total
FROM orders
GROUP BY month ORDER BY month
How do I get the last one? In the app, I get the sum via the following Ruby code:
order_subtotal = order.items.map{|item| item.price * item.quantity}.reduce(:+)
Which basically takes all the order's items, multiplies price by quantity and adds the results.
This should be a good start:
SELECT Date_trunc('month', created_at) :: DATE AS month,
SUM(service_fee_cents) / 100 AS total_service_fee,
SUM(grand_total_cents) / 100 AS total_grand_total,
SUM(total_subtotal) / 100 AS total_subtotals
FROM orders o
join (SELECT order_id,
SUM(price_cents * quantity) total_subtotal
FROM items i
GROUP BY order_id) i
ON o.id = i.order_id
GROUP BY month
ORDER BY month
You can get there by just joining the Orders table to the Items table and generating a SUM of subtotals by month. This may however be a somewhat expensive query to run if there are thousands of items in each order like you said.
SELECT
date_trunc('month', created_at)::date AS month,
SUM(service_fee_cents) / 100 AS total_service_fee,
SUM(grand_total_cents) / 100 AS total_grand_total,
SUM(price_cents * quantity) / 100 AS sub_total
FROM Orders o
JOIN Items i ON i.order_id = o.id
GROUP BY month ORDER BY month
http://sqlfiddle.com/#!15/555a2/1

postgresql - Change single row to multiple rows

I have a table named payment_info, with the following records.
paymentid | customercode | previousbalance | paymentamount | remainingbalance
-----------------------------------------------------------------------------
PID0001 | CUST024 | 10000 | 2500 | 7500
PID0002 | CUST031 | 8500 | 3500 | 5000
PID0003 | CUST005 | 12000 | 1500 | 10500
Then what I want is to create a 3 rows per row of the above table.
I want my results to look like this.
Payment Group | Payment Line Item | Payment ID | Customer Code | Type | Amount
--------------------------------------------------------------------------------------------------
1 | 1 | PID0001 | CUST024 | PREVIOUS BALANCE | 10000.00
1 | 2 | | | PAYMENT AMOUNT | 2500.00
1 | 3 | | | REMAINING BALANCE | 7500.00
2 | 1 | PID0002 | CUST031 | PREVIOUS BALANCE | 8500.00
2 | 2 | | | PAYMENT AMOUNT | 3500.00
2 | 3 | | | REMAINING BALANCE | 5000.00
3 | 1 | PID0003 | CUST005 | PREVIOUS BALANCE | 12000.00
3 | 2 | | | PAYMENT AMOUNT | 1500.00
3 | 3 | | | REMAINING BALANCE | 10500.00
Here is the query I've started. But it did not return results same as above.
select row_number() over() as id,paymentid,customercode,'PREVIOUS BALANCE' as type,previousbalance from payment_info
union
select row_number() over() as id,'','','PAYMENT AMOUNT' as type,paymentamount from payment_info
union
select row_number() over() as id,'','','REMAINING BALANCE' as type,remainingbalance from payment_info
Is there other ways, where I will not use UNION Keyword? Cause in the real table, I will be using 30+ columns, querying thousands of records.
I also don't know how to create auto generated number (id) from payment group (per payment id) and Payment Line Item (per group).
thanks
version with whitespace (empty text)
The unnest function can do this for you.
And if you want the empty text then you can use this
SELECT ROW_NUMBER() OVER (ORDER BY paymentid) AS "group",
unnest(array[1, 2, 3]) AS "line item",
unnest(array[paymentid, '', '']) AS "paymentid",
unnest(array[customercode, '', '']) AS "customercode",
unnest(array['PREVIOUS BALANCE', 'PAYMENT AMOUNT', 'REMAINING BALANCE']) AS "type",
unnest(array[previousbalance, paymentamount, remainingbalance]) AS "amount"
FROM payment_info
ORDER BY 1, 2 ;
To get this
group | line item | paymentid | customercode | type | amount
-------+-----------+-----------+--------------+-------------------+--------
1 | 1 | PID0001 | CUST024 | PREVIOUS BALANCE | 10000
1 | 2 | | | PAYMENT AMOUNT | 2500
1 | 3 | | | REMAINING BALANCE | 7500
2 | 1 | PID0002 | CUST031 | PREVIOUS BALANCE | 8500
2 | 2 | | | PAYMENT AMOUNT | 3500
2 | 3 | | | REMAINING BALANCE | 5000
3 | 1 | PID0003 | CUST005 | PREVIOUS BALANCE | 12000
3 | 2 | | | PAYMENT AMOUNT | 1500
3 | 3 | | | REMAINING BALANCE | 10500
If you want to have, for example points or other text, or arrows in the empty text columns, you can do this easily with unnest.
You can control the 4 empty text values individually.
SELECT ROW_NUMBER() OVER (ORDER BY paymentid) AS "group",
unnest(array[1, 2, 3]) AS "line item",
unnest(array[paymentid, ' a', ' c']) AS "paymentid",
unnest(array[customercode, ' b', ' d']) AS "customercode",
unnest(array['PREVIOUS BALANCE', 'PAYMENT AMOUNT', 'REMAINING BALANCE']) AS "type",
unnest(array[previousbalance, paymentamount, remainingbalance]) AS "amount"
FROM payment_info
ORDER BY 1, 2 ;
to generate
group | line item | paymentid | customercode | type | amount
-------+-----------+-----------+--------------+-------------------+--------
1 | 1 | PID0001 | CUST024 | PREVIOUS BALANCE | 10000
1 | 2 | a | b | PAYMENT AMOUNT | 2500
1 | 3 | c | d | REMAINING BALANCE | 7500
2 | 1 | PID0002 | CUST031 | PREVIOUS BALANCE | 8500
2 | 2 | a | b | PAYMENT AMOUNT | 3500
2 | 3 | c | d | REMAINING BALANCE | 5000
3 | 1 | PID0003 | CUST005 | PREVIOUS BALANCE | 12000
3 | 2 | a | b | PAYMENT AMOUNT | 1500
3 | 3 | c | d | REMAINING BALANCE | 10500
It's a very flexible solution, you know.
It isn't necessary to always use union queries. Here for example you can use 3 rows and a cross join instead. This has the advantage of only a single pass over the source table.
drop table if exists Table1;
CREATE TABLE Table1
("paymentid" varchar(7), "customercode" varchar(7)
, "previousbalance" int, "paymentamount" int, "remainingbalance" int)
;
INSERT INTO Table1
("paymentid", "customercode", "previousbalance", "paymentamount", "remainingbalance")
VALUES
('PID0001', 'CUST024', 10000, 2500, 7500),
('PID0002', 'CUST031', 8500, 3500, 5000),
('PID0003', 'CUST005', 12000, 1500, 10500)
;
select
paymentid
, customercode
, rn
, typeof
, case when rn = 1 then previousbalance
when rn = 2 then paymentamount
when rn = 3 then remainingbalance
end as Amount
from Table1
cross join (select 1 rn , 'previousbalance' typeof
union all
select 2 , 'paymentamount'
union all
select 3, 'remainingbalance'
) rns
That data/query produces this result:
+----+-----------+--------------+----+------------------+--------+
| | paymentid | customercode | rn | typeof | amount |
+----+-----------+--------------+----+------------------+--------+
| 1 | PID0001 | CUST024 | 1 | previousbalance | 10000 |
| 2 | PID0001 | CUST024 | 2 | paymentamount | 2500 |
| 3 | PID0001 | CUST024 | 3 | remainingbalance | 7500 |
| 4 | PID0002 | CUST031 | 1 | previousbalance | 8500 |
| 5 | PID0002 | CUST031 | 2 | paymentamount | 3500 |
| 6 | PID0002 | CUST031 | 3 | remainingbalance | 5000 |
| 7 | PID0003 | CUST005 | 1 | previousbalance | 12000 |
| 8 | PID0003 | CUST005 | 2 | paymentamount | 1500 |
| 9 | PID0003 | CUST005 | 3 | remainingbalance | 10500 |
+----+-----------+--------------+----+------------------+--------+
Please then note that SQL isn't a "report writer" so blanks in columns for "layout" are not a good fit for SQL which wants to repeat information (like you see above in the result) so that you can sort and filter as needed.

SQL Server 2014 - How to calculate percentage based on last NOT NULL value in a column?

I have the following table dates, items and sales as show below :
table Dates :
+---------+------------+------------+
| Date_ID | StartDates | EndDates |
+---------+------------+------------+
| 1 | 2016-07-01 | 2016-07-05 |
| 2 | 2016-07-06 | 2016-07-12 |
+---------+------------+------------+
table items :
+--------+----------+---------+
| ITM_ID | ITM_Name | ITM_Qty |
+--------+----------+---------+
| A0001 | Item A | 30 |
| B0001 | Item B | 50 |
+--------+----------+---------+
table sales :
+----------+------------+------------+-----------+
| Sales_ID | Sales_Date | Sales_Item | Sales_Qty |
+----------+------------+------------+-----------+
| S0001 | 2016-07-02 | A | 5 |
| S0002 | 2016-07-04 | A | 15 |
| S0003 | 2016-07-08 | B | 20 |
| S0004 | 2016-07-12 | A | 10 |
+----------+------------+------------+-----------+
I would like to calculate a percentage (act like a ratio of sales on current period compared to the previous period) and the available amount of item after each sales.
My expected output would be like this :
+------------+------------+---------+----------+----------+-----------+
| StartDates | EndDates | Item_ID | Sold_Qty | Percents | Available |
+------------+------------+---------+----------+----------+-----------+
| 2016-07-01 | 2016-07-05 | A0001 | 20 | 100 | 10 |
| 2016-07-01 | 2016-07-05 | B0001 | 0 | 0 | 50 |
| 2016-07-06 | 2016-07-12 | A0001 | 10 | 50 | 0 |
| 2016-07-06 | 2016-07-12 | B0001 | 20 | 100 | 30 |
+------------+------------+---------+----------+----------+-----------+
I hope the expected output will be possible but I have currently not get a working query yet.
As the table above, the column percents is a percentage sales of current period compared to the last period, i.e. on item A0001 first period has sold_qty is 20 and the second period is 10, therefore the percentage of second period is (10/20) * 100 = 50.
EDIT : for the case of item B0001, the sold_qty of the first period is 0, therefore the percentage count should not consider the value on the first period.
Try Below. For Calculating Percents i have used case statement that you can simplify it based on your requirement.
SELECT *,
CASE
WHEN SOLD_QTY = 0 THEN 0
WHEN LAG(SOLD_QTY)
OVER(
PARTITION BY ITM_ID
ORDER BY ITM_ID) = 0
OR LAG(SOLD_QTY)
OVER(
PARTITION BY ITM_ID
ORDER BY ITM_ID) IS NULL THEN 100
ELSE CONVERT(FLOAT, SOLD_QTY) / NULLIF(LAG(SOLD_QTY)
OVER(
PARTITION BY ITM_ID
ORDER BY ITM_ID), 0) * 100
END PERCENTS
FROM (SELECT T1.STARTDATES,
T1.ENDDATES,
T2.ITM_ID,
ISNULL(SUM(T3.SALES_QTY), 0) SOLD_QTY,
( T2.[ITM_QTY] ) - ISNULL(SUM(T3.SALES_QTY), 0)AS AVIL
FROM #TABLE1 T1
CROSS JOIN #TABLE2 T2
LEFT JOIN #TABLE3 T3
ON T3.[SALES_ITEM] = LEFT(T2.[ITM_ID], 1)
AND T3.SALES_DATE BETWEEN T1.STARTDATES AND T1.ENDDATES
GROUP BY T1.STARTDATES,
T1.ENDDATES,
T2.ITM_ID,
T2.[ITM_QTY])A

MS Access SQL getting results from different tables and sorting by date

i hope my description will be enough. i tried to remove all non-significant fields.
i have 5 tables (Customer, Invoice, Items, Invoice_Item, Payment):
Customer fields and sample date are:
+----+------+
| ID | Name |
+----+------+
| 1 | John |
| 2 | Mary |
+----+------+
Invoice fields and sample date are:
+----+-----------+----------+------+
| ID | Date | Customer | Tax |
+----+-----------+----------+------+
| 1 | 1.1.2017 | 1 | 0.10 |
| 2 | 2.1.2017 | 2 | 0.10 |
| 3 | 3.1.2017 | 1 | 0.10 |
| 4 | 3.1.2017 | 2 | 0.10 |
| 5 | 8.1.2017 | 1 | 0.10 |
| 6 | 11.1.2017 | 1 | 0.10 |
| 7 | 12.1.2017 | 2 | 0.10 |
| 8 | 13.1.2017 | 1 | 0.10 |
+----+-----------+----------+------+
Item fields and sample data are:
+----+--------+
| ID | Name |
+----+--------+
| 1 | Door |
| 2 | Window |
| 3 | Table |
| 4 | Chair |
+----+--------+
Invoice_Item fields and sample data are:
+------------+---------+--------+------------+
| Invoice_ID | Item_ID | Amount | Unit_Price |
+------------+---------+--------+------------+
| 1 | 1 | 4 | 10 |
| 1 | 2 | 2 | 20 |
| 1 | 3 | 1 | 30 |
| 1 | 4 | 2 | 40 |
| 2 | 1 | 1 | 10 |
| 2 | 3 | 1 | 15 |
| 2 | 4 | 2 | 12 |
| 3 | 3 | 4 | 15 |
| 4 | 1 | 1 | 10 |
| 4 | 2 | 20 | 30 |
| 4 | 3 | 15 | 30 |
| 5 | 1 | 4 | 10 |
| 5 | 2 | 2 | 20 |
| 5 | 3 | 1 | 30 |
| 5 | 4 | 2 | 40 |
| 6 | 1 | 1 | 10 |
| 6 | 3 | 1 | 15 |
| 6 | 4 | 2 | 12 |
| 7 | 3 | 4 | 15 |
| 8 | 1 | 1 | 10 |
| 8 | 2 | 20 | 30 |
| 8 | 3 | 15 | 30 |
+------------+---------+--------+------------+
The reason the price is in this table not in the item table is because it is customer specific price.
Payment fields are:
+----------+--------+-----------+
| Customer | Amount | Date |
+----------+--------+-----------+
| 1 | 40 | 3.1.2017 |
| 2 | 10 | 7.1.2017 |
| 1 | 60 | 10.1.2017 |
+----------+--------+-----------+
so my report should be combine all tables and sort by DATE (either from Invoice or Payment) for a certain customer.
so for e.g. for customer John (1) it should be like:
+------------+----------------+---------+-----------+
| Invoice_ID | Invoice_Amount | Payment | Date |
+------------+----------------+---------+-----------+
| 1 | 171 | - | 1.1.2017 |
| 3 | 54 | - | 3.1.2017 |
| - | - | 40 | 3.1.2017 |
| 5 | 171 | - | 8.1.2017 |
| - | 10 | 60 | 10.1.2017 |
| 6 | 44.1 | - | 11.1.2017 |
| 8 | 954 | - | 13.1.2017 |
+------------+----------------+---------+-----------+
it is sorted by date, Invoice amount is (sum of (Amount* unit price)) * (1-tax)
i started with union but then got lost.
here is my try:
SELECT Inv_ID as Num, SUM(Invoice_Items.II_Price*Invoice_Items.II_Amount) AS Amount, Inv_Date as Created
FROM Invoice INNER JOIN Invoice_Items ON Invoice.Inv_ID = Invoice_Items.II_Inv_ID
UNION ALL
SELECT Null as Num, P_Value as Amount, P_Date as Created
FROM Payments
ORDER BY created ASC
Your help is appreciated!
Thanks
You can generate the report you requested using the following SQL script:
SELECT CustomerID,Invoice_ID,Invoice_Amount,Payment,Date
FROM (
SELECT c.ID AS CustomerID, i.ID AS Invoice_ID, SUM((t.Amount * t.UnitPrice)*(1-i.tax)) AS Invoice_Amount, NULL AS Payment,i.Date
FROM (Customer c
LEFT JOIN Invoice i
ON c.ID = i.Customer)
LEFT JOIN Invoice_Item t
ON i.ID = t.Invoice_ID
GROUP BY c.ID, i.ID,i.Date
UNION
SELECT c.ID AS CustomerID,NULL AS Invoice_ID, NULL AS Invoice_Amount, p.Amount AS Payment, p.Date
FROM Customer c
INNER JOIN Payment p
ON c.ID = p.Customer ) a
ORDER BY CustomerID, Date, Payment ASC
Note: I've added CustomerID to the output so you know what customer the data corresponds to.
here is the Answer which worked for me, a bit corrected from #Catzeye Answer , which didnt show the second part of the Union.
SELECT c.ID AS CustomerID,NULL AS Invoice_ID, NULL AS Invoice_Amount, p.Amount AS Payment, p.Date
FROM Customer c
INNER JOIN Payment p
ON c.ID = p.Customer
UNION ALL
SELECT c.ID AS CustomerID, i.ID AS Invoice_ID, SUM((t.Amount * t.Unit_Price)*(1-i.tax)) AS Invoice_Amount, NULL AS Payment,i.Date
FROM (Customer c
INNER JOIN Invoice i
ON c.ID = i.Customer)
INNER JOIN Invoice_Item t
ON i.ID = t.Invoice_ID
GROUP BY c.ID, i.ID,i.Date
ORDER BY CustomerID, Date, Payment;

SQL Join Help - Sum and Apply Filter to Tables Before Join

I have a Stock View (that lists all the individual pieces of stock and the stock date) and a Sales View (that lists all of the sales and the date the sale occurred).
Stock View:
+----+------+-----+------------+
| ID | Item | Qty | Date |
+----+------+-----+------------+
| 1 | A | 3 | 01/01/2000 |
| 2 | A | 2 | 02/02/2000 |
| 3 | D | 9 | 05/06/2000 |
| 4 | F | 22 | 09/01/2001 |
| 5 | A | 10 | 01/04/2001 |
| 6 | C | 12 | 01/01/2002 |
+----+------+-----+------------+
Sales View:
+------+-----+------------+
| Item | Qty | Date |
+------+-----+------------+
| B | 3 | 01/01/2001 |
| B | 77 | 01/12/2001 |
| C | 9 | 02/02/2002 |
| A | 10 | 03/03/2002 |
| G | 2 | 05/06/2002 |
| C | 3 | 09/10/2012 |
+------+-----+------------+
I want to join these tables..but before doing so:
Stock view needs to be filtered between 2 date parameters #StockFrom and #StockTo
Sales view needs to be filtered between 2 date parameters #SalesFrom and #SalesTo
Sales view then needs to be grouped by Item and have the Qty Summed (so the date field needs to be dropped although it is being filtered on) and then joined onto the Stock View on the Item field.
So in essence I want to see the Stock View as it is (but filtered on dates) with an extra column showing the sales that have occurred between 2 dates for that item.
Desired Output:
+----+------+-----+------------+-------+
| ID | Item | Qty | Date | Sales |
+----+------+-----+------------+-------+
| 1 | A | 3 | 01/01/2000 | 10 |
| 2 | A | 2 | 02/02/2000 | 10 |
| 3 | D | 9 | 05/06/2000 | 0 |
| 4 | F | 22 | 09/01/2001 | 0 |
| 5 | A | 10 | 01/04/2001 | 10 |
| 6 | C | 12 | 01/01/2002 | 12 |
+----+------+-----+------------+-------+
Thanks to any help in advance!
SELECT
Stock.*,
IFNULL(SUM(Sales.Qty),0) AS Sales
FROM Stock
LEFT JOIN Sales ON Stock.Item=Sales.Item
WHERE Stock.Date BETWEEN #StockFrom AND #StockTo
AND (
Sales.Date BETWEEN #SalesFrom AND #SalesTo
OR Sales.Date IS NULL
)
GROUP BY Stock.ID
This is for MySQL, as you didn't specify the diaclect. SQLfiddle
EDIT
SELECT
Stock.ID AS ID,
MIN(Stock.Item) AS Item,
MIN(Stock.Qty) AS Qty,
MIN(Stock.Date) AS Date,
CASE WHEN SUM(Sales.Qty) IS NULL THEN 0 ELSE SUM(Sales.Qty) END AS Sales
FROM Stock
LEFT JOIN Sales ON Stock.Item=Sales.Item
WHERE Stock.Date BETWEEN #StockFrom AND #StockTo
AND (
Sales.Date BETWEEN #SalesFrom AND #SalesTo
OR Sales.Date IS NULL
)
GROUP BY Stock.ID
works for MS SQL (SQLfiddle)
Please try below query for MS Sql Server:
SELECT DISTINCT
a.ID,
a.Item,
a.Qty,
a.Date,
ISNULL(SUM(b.Qty) OVER (PARTITION BY a.Item, a.[Date]), 0) Sales
FROM
StockView a LEFT JOIN SalesView b on a.Item=b.Item