I have the following SQL statement which shows me transactions from a Point Of Sale system. I would like to calculate the total sum of (MoneyIn - MoneyOut) columns but is a bit beyond me and show this as a single value. I am sure its a simple mod to this.
DECLARE #StartDate DateTime;
DECLARE #EndDate DateTime;
DECLARE #SearchTerm NVARCHAR(200);
SET #SearchTerm = '%widget1%'
SET #StartDate = '2018-05-01 00:00:00'
SET #EndDate = DATEADD(month, 1, #StartDate)
SELECT TOP (500)
t.TransactionDate,
t.MoneyIn,
t.MoneyOut,
t.Description,
p.PaymentMethodName,
t.TransactionRef,
c.SalesItems,
COUNT(*) AS Occurrences
FROM
Transactions t
LEFT JOIN
Tills tl ON t.TillId = tl.TillId
INNER JOIN
PaymentMethods p ON t.PaymentMethodId = p.PaymentMethodsID
INNER JOIN
Membership m ON t.UserId = m.UserId
CROSS APPLY
(SELECT
STUFF((SELECT ',' + CAST(tp.Description AS VARCHAR(100))
FROM TransactionsPosLines tp
WHERE t.TransactionId = tp.TransactionId
FOR XML PATH('')), 1, 1, '') AS SalesItems) c
WHERE
t.TransactionDate >= #StartDate
AND t.TransactionDate <= #EndDate
AND (t.PaymentTypeId = 1)
AND SalesItems LIKE #SearchTerm
GROUP BY
t.TransactionDate,
t.MoneyIn,
t.MoneyOut,
t.Description,
p.PaymentMethodName,
t.TransactionRef,
m.Username,
c.SalesItems
ORDER BY
COUNT(*) DESC
Output:
2018-05-01 17:23:23.243 9.99 0.00 Sale - Card Card Shop Sale Grab n Go item 1
2018-05-08 13:15:04.577 10.00 -0.01 Sale - Cash Total: 9.99 Cash Shop Sale Grab n Go item 1
2018-05-10 14:08:47.120 7.99 0.00 Sale - Card Card Shop Sale Grab n Go item,Discount 1
and I want to show:
Total Sales: 27.97
(Sum of MoneyIn - Sum of MoneyOut)
So that this question has an answer
(edit: added the actual SQL I used to resolve this which gave the single result I was looking for), thanks for help:
Select top (10000)
sum(t.MoneyIn) - sum(t.MoneyOut) as 'moneytotal'
From
Transactions t
LEFT JOIN Tills tl
ON t.TillId = tl.TillId
INNER JOIN PaymentMethods p
ON t.PaymentMethodId = p.PaymentMethodsID
INNER JOIN Membership m
On t.UserId = m.UserId
CROSS APPLY
(SELECT STUFF(
(SELECT ',' + CAST(tp.Description AS VARCHAR(100))
FROM
TransactionsPosLines tp
WHERE t.TransactionId = tp.TransactionId
FOR XML PATH(''))
,1,1,'') as SalesItems) c
Where
t.TransactionDate >= #StartDate
AND t.TransactionDate <= #EndDate
AND (t.PaymentTypeId = 1)
and SalesItems LIKE #SearchTerm
Order By
count(*) Desc
GO
Related
I have a search engine where the user will specify multiple conditions and based on these conditions i will return a datatable.
The problem I am facing is that the conditions are not respected and I am getting wrong results.
I have tried to test every condition alone, it is working, but when I put all the conditions together, I am getting unexpected results.
USE [Tenant Management]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[RentSearchEngine]
#sqm INT,
#category INT,
#shortRentPrice MONEY,
#longRentPrice MONEY,
#fromDate DATETIME,
#toDate DATETIME
AS
BEGIN
SET NOCOUNT ON;
SELECT
c.[Name], cate.[Channel Category], tp.type, st.Status, c.Surface,
g.GOVERNATOR + ' ' + d.District + ' ' + cit.City + ' ' as [Address],
c.[Short term Price per night] AS [Short term monthly amount],
c.[Long term price per month] AS [Long term monthly amount],
c.[Selling Price]
FROM
[dbo].[Channel] c
INNER JOIN
[dbo].[Governator] g ON c.[Governator ID] = g.ID
INNER JOIN
[dbo].[District] d ON c.[District ID] = d.ID
INNER JOIN
[dbo].[City] cit ON c.[City ID] = cit.id
INNER JOIN
[dbo].[Channel_Category] cate ON c.[Channel Category ID] = cate.ID
INNER JOIN
[dbo].[Channel_Type] tp ON c.[Channel Type] = tp.id
INNER JOIN
[dbo].[Channel_Status] st ON c.[Channel Status] = st.ID
LEFT JOIN
[dbo].[Reservations] r ON c.[ID] = r.[Channel ID]
WHERE
c.[Channel Status] = '5'
AND c.[Channel Type] = '1'
AND c.[Channel Category ID] = #category OR #category IS NULL
AND c.Surface BETWEEN #sqm * 0.85 AND #sqm * 1.15 OR #sqm IS NULL
AND c.[Long term price per month] BETWEEN #longRentPrice * 0.85
AND #longRentPrice * 1.15 OR #longRentPrice IS NULL
AND c.[Short term Price per night] BETWEEN #shortRentPrice * 0.85
AND #shortRentPrice * 1.15 OR #shortRentPrice IS NULL
AND (r.[Actual Date in] > #fromDate AND r.[Actual Date out] > #toDate)
AND (r.[Actual Date in] < #fromDate AND r.[Actual Date out] < #toDate)
END
The current result is:
fdfd Residential apatment For Rent Available 500 Mont Liban Baabda Ain El Remmaneh 1287182.00 28712.00 128712.00
When executing the stored procedure as follow:
DECLARE #return_value int
EXEC #return_value = [dbo].[RentSearchEngine]
#sqm = 40000,
#category = 1,
#shortRentPrice = 5,
#longRentPrice = 4,
#fromDate = NULL,
#toDate = NULL
SELECT 'Return Value' = #return_value
I think the key issue is the operator preference for AND & OR.
Bear in mind that AND has higher preference than OR.
In these complex conditions is a good practise to ensure the order with parenthesis.
I will write what I understand you are trying to achieve but ensure you use the parenthesis in the order you require:
where c.[Channel Status] = '5'
and c.[Channel Type] = '1'
and (c.[Channel Category ID] =#category or #category IS NULL)
and (c.Surface between #sqm*0.85 and #sqm*1.15 or #sqm IS NULL)
and (c.[Long term price per month] between #longRentPrice*0.85 and #longRentPrice*1.15 or #longRentPrice IS NULL)
and (c.[Short term Price per night] between #shortRentPrice*0.85 and #shortRentPrice*1.15 or #shortRentPrice IS NULL)
and (r.[Actual Date in] > #fromDate and r.[Actual Date out] > #toDate)
and (r.[Actual Date in] < #fromDate and r.[Actual Date out] < #toDate)
I have to get the list of months and year in between my dates. Currently it only returns month and year for dates that has data associated with it.
for example my dates is between: '8'+'/1'+'/'+'2015' and DATEADD(mm, 15, '8'+'/1'+'/'+'2016'
It only prints out: May2016, June2016, July2016, Auguest2016, September2016
I want it to print out all of the months and year in between. Here is my sql queries:
select d.id_base as case_id,
c.C_LAST_ACTION AS Docketed,
c.C_CASE_TYPE AS caseType,
ct.C_NAME As caseName,
ct.C_DESCRIPTION AS caseNameDescription,
case when d.c_mod_decision_id is not null then '' else DATENAME(mm, d.c_issue_date) + DATENAME(yyyy, d.c_issue_date) end as display
from t_case_decision d JOIN T_CASE_INPUT c on c.id = d.id_base JOIN T_CASE_TYPE ct on C_CASE_TYPE = ct.id
where cast(d.c_issue_date AS date) BETWEEN '8'+'/1'+'/'+'2015' and DATEADD(mm, 15, '8'+'/1'+'/'+'2016')
First, create a numbers table
CREATE TABLE Numbers(N INT)
insert into Numbers(N)
select top 1000000 row_number() over(order by t1.number) as N
from master..spt_values t1
cross join master..spt_values t2
then use DATEADD to list dates between desired values, like this
declare #iniDate as date
set #iniDate='20150801'
select dateadd(MONTH,N,#iniDate) dates
from Numbers
where N<15 order by N
These returns dates from #iniDate up to 15 months later
EDIT: try this, I don't have sql right now
select datename(mm, dateadd(MONTH,N,#iniDate))+datename(yyyy ,dateadd(MONTH,N,#iniDate)) display
from ( select top 15row_number() over(order by t1.number) as N
from master..spt_values t1
cross join master..spt_values t2) numbers right join (
select d.id_base as case_id,
c.C_LAST_ACTION AS Docketed,
c.C_CASE_TYPE AS caseType,
ct.C_NAME As caseName,
ct.C_DESCRIPTION AS caseNameDescription,
case when d.c_mod_decision_id is not null then '' else DATENAME(mm, d.c_issue_date) + DATENAME(yyyy, d.c_issue_date) end as display
from t_case_decision d JOIN T_CASE_INPUT c on c.id = d.id_base JOIN T_CASE_TYPE ct on C_CASE_TYPE = ct.id
where cast(d.c_issue_date AS date) BETWEEN '8'+'/1'+'/'+'2015' and DATEADD(mm, 15, '8'+'/1'+'/'+'2016')
sql-server
) qq
on datename(mm, dateadd(MONTH,N,#iniDate))+datename(yyyy ,dateadd(MONTH,N,#iniDate)) = qq.display
where N<15 order by N
If I understand what you're trying to accomplish, a recursive CTE might help. Here's a quick example of what you can do. The CTE will expand out into a list of dates, which you can then use as the base for your query.
The contents of the TargetData CTE may need to be adjusted, as I don't have a complete picture of your data structure.
DECLARE #startDate DATE = '1/1/2015';
DECLARE #endDate DATE = '7/31/2016';
-- Recursive CTE to generate a list of months within the date range:
WITH Months AS (
SELECT CONVERT(DATE, DATEADD(D, -(DAY(#startDate)) + 1, #startDate)) [MonthDate]
UNION ALL
SELECT DATEADD(M, 1, MonthDate)
FROM Months
WHERE MonthDate <= DATEADD(M, -1, #endDate)
),
TargetData AS (
-- This is a slightly modified version of the original query:
select
d.id_base as case_id,
c.C_LAST_ACTION AS Docketed,
c.C_CASE_TYPE AS caseType,
ct.C_NAME As caseName,
ct.C_DESCRIPTION AS caseNameDescription,
case when d.c_mod_decision_id is not null then '' else DATENAME(mm, d.c_issue_date) + DATENAME(yyyy, d.c_issue_date) end as display,
-- Return the "MonthDate" so that it can be left joined to the Months table:
DATEADD(D, -(DAY(d.c_issue_date)) + 1, d.c_issue_date) [MonthDate]
from t_case_decision d JOIN T_CASE_INPUT c on c.id = d.id_base JOIN T_CASE_TYPE ct on C_CASE_TYPE = ct.id
where cast(d.c_issue_date AS date) BETWEEN #startDate AND #endDate
)
SELECT
m.MonthDate,
DATENAME(mm, m.MonthDate) + DATENAME(yyyy, m.MonthDate),
td.*
FROM Months m
LEFT JOIN TargetData td ON td.MonthDate = m.MonthDate;
You need to join on primary keys between tables, I haven't seen a between statement with that syntax. So I suggest trying the following:
SELECT d.id_base as case_id, c.C_LAST_ACTION AS 'Docketed',c.C_CASE_TYPE AScaseType,ct.C_NAME As 'caseName', ct.C_DESCRIPTION AS 'caseNameDescription'
,CASE
WHEN d.c_mod_decision_id is not null THEN '' AS 'null_val'
ELSE CONCAT(YEAR(d.c_issue_dateDATENAME), MONTH(d.c_issue_date))
END AS 'display'
FROM t_case_decision d INNER JOIN T_CASE_INPUT c on c.id = d.id_base
INNER JOIN T_CASE_TYPE ct on c.id = ct.id
WHERE CONVERT(DATE,d.c_issue_date) BETWEEN '08/01/2015'
AND '08/01/2016';
I hope this helps or points you in the right direction :)
The following query gives playing time of the users from the database on daily basis for the last 15 days. It adds 0 if no game is played. Now I want to get the data of playing time on weekly basis and 0 if no game is played in the whole week. So I want the query to give the last 15 weeks of data.
Here is the daily query.
CREATE PROCEDURE [dbo].[spGetPlayingTimeOfthepeoplesPerDay] #email NVARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #MinDate DATE
,#MaxDate DATE
,#LastXDays INT
SELECT #LastXDays = - 15
SELECT #MaxDate = peoples.l_update
FROM peoples
WHERE peoples.email = #email
DECLARE #test TABLE (
quantity VARCHAR(100)
,DATE DATE
,TimePerDay DECIMAL(5, 2)
);
WITH CTE
AS (
SELECT peoples.email
,peoples.l_update
,act.quantity
,act.starttime
,act.endtime
,act.duration AS [Totaltime]
FROM peoples
INNER JOIN MPeoples ON peoples.Id = MPeoples.parent_id
INNER JOIN slines ON MPeoples.id = slines.movesuser_id
INNER JOIN seg ON slines.id = seg.sline_id
INNER JOIN act ON seg.id = act.seg_id
WHERE act.quantity = 'playing'
AND (peoples.email = #email)
GROUP BY peoples.email
,act.quantity
,act.duration
,act.starttime
,act.endtime
,peoples.l_update
)
INSERT INTO #test (
quantity
,DATE
,TimePerDay
)
SELECT quantity
,Cast(starttime AS DATE) AS DATE
,SUM(datediff(second, starttime, endtime)) / 60.0 AS TimePerDay
FROM cte WITH (NOLOCK)
WHERE starttime >= dateadd(day, #LastXDays, l_update)
GROUP BY quantity
,cast(starttime AS DATE)
SELECT #MaxDate = #MaxDate
,#MinDate = dateadd(day, (#LastXDays + 1), #MaxDate);
WITH AllDates
AS (
SELECT #MinDate AS xDate
UNION ALL
SELECT Dateadd(Day, 1, xDate)
FROM AllDates AS ad
WHERE ad.xDate < #MaxDate
)
SELECT 'playing' AS quantity
,ad.xDate
,Isnull(t.TimePerDay, 0) AS TimePerDay
FROM AllDates AS ad WITH (NOLOCK)
LEFT JOIN #test AS t ON ad.xDate = t.DATE
END
Change the DATEADD from day to week. Hence, two changes:
dateadd(week, #LastXDays, l_update)
and
dateadd(week, (#LastXDays + 1), #MaxDate)
In this case, I would also rename the #LastXDays variable to #LastXWeeks.
CREATE PROCEDURE [dbo].[spGetPlayingTimeOfthepeoplesPerDay] #email NVARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #MinDate DATE
,#MaxDate DATE
,#LastXDays INT
SELECT #LastXWeeks = - 15
SELECT #MaxDate = peoples.l_update
FROM peoples
WHERE peoples.email = #email
DECLARE #test TABLE (
quantity VARCHAR(100)
,DATE DATE
,TimePerDay DECIMAL(5, 2)
);
WITH CTE
AS (
SELECT peoples.email
,peoples.l_update
,act.quantity
,act.starttime
,act.endtime
,act.duration AS [Totaltime]
FROM peoples
INNER JOIN MPeoples ON peoples.Id = MPeoples.parent_id
INNER JOIN slines ON MPeoples.id = slines.movesuser_id
INNER JOIN seg ON slines.id = seg.sline_id
INNER JOIN act ON seg.id = act.seg_id
WHERE act.quantity = 'playing'
AND (peoples.email = #email)
GROUP BY peoples.email
,act.quantity
,act.duration
,act.starttime
,act.endtime
,peoples.l_update
)
INSERT INTO #test (
quantity
,DATE
,TimePerDay
)
SELECT quantity
,Cast(starttime AS DATE) AS DATE
,SUM(datediff(second, starttime, endtime)) / 60.0 AS TimePerDay
FROM cte WITH (NOLOCK)
WHERE starttime >= dateadd(week, #LastXWeeks, l_update)
GROUP BY quantity
,cast(starttime AS DATE)
SELECT #MaxDate = #MaxDate
,#MinDate = dateadd(week, (#LastXWeeks + 1), #MaxDate);
WITH AllDates
AS (
SELECT #MinDate AS xDate
UNION ALL
SELECT Dateadd(Day, 7, xDate)
FROM AllDates AS ad
WHERE ad.xDate < #MaxDate
)
SELECT 'playing' AS quantity
,ad.xDate
,Isnull(t.TimePerDay, 0) AS TimePerDay
FROM AllDates AS ad WITH (NOLOCK)
LEFT JOIN #test AS t ON ad.xDate = t.DATE
END
Also, a piece of advice: don't use query hints (NOLOCK) if you do not understand their use. In this case, using NOLOCK can have disastrous effects on your results.
Here are a few articles which you should read before deciding if you are going to keep using NOLOCK or not.
Understanding the SQL Server NOLOCK hint
Bad habits : Putting NOLOCK everywhere
Table structure:
This is the data for which i want to use pivot table
i want to display the result as
Teacher Activity [2013-11-22] and so on The date field will display the count of the attendance.
Below is the code which i am using, result is coming as 0 under every date, which is not correct:
DECLARE #temp AS TABLE(dates datetime)
;with cte (datelist, maxdate) as
(
select DATEADD(dd,-3,GETDATE()), GETDATE()
union all
select dateadd(dd, 1, datelist), maxdate
from cte
where datelist < maxdate
)
INSERT INTO #temp
SELECT c.datelist
FROM cte c
DECLARE #listdate nvarchar(MAX)
SELECT #listdate = (select(STUFF( (SELECT ', ' + QUOTENAME(convert(CHAR(10), dates, 120))
from #temp ORDER BY dates asc
FOR XML PATH('')),1, 1, '')))
print #listdate
exec('(SELECT * INTO ##temptable from
(select distinct teachername as Teacher,activityname AS Activity,memberid as attendance,
QUOTENAME(convert(CHAR(10), attendancedate, 120)) AS DATES from
tbteachertimelog inner join tbteacher on
teacherid = tbteacher.id
inner join tbactivity on tbactivity.id = tbteachertimelog.activityid
left join tbattendance on tbattendance.activityid = tbteachertimelog.activityid and
convert(CHAR(10), tbattendance.attendancedate, 120) = convert(CHAR(10), tbteachertimelog.date, 120)
group by teachername,activityname,memberid,
attendancedate
) p
PIVOT
(
count(attendance)
FOR DATES IN ('+#listdate+')) AS pvt
)
')
alter table ##temptable add TotalStudents int,meetings int,total64 int
update ##temptable set TotalStudents =
(SELECT SUM(memcount) FROM (select count(distinct memberid) as memcount from tbteachertimelog
inner join tbattendance on tbattendance.activityid = tbteachertimelog.activityid and
convert(CHAR(10), tbattendance.attendancedate, 120) = convert(CHAR(10), tbteachertimelog.date, 120)
where --teacherid = ##temptable.teacherid and tbteachertimelog.activityid = ##temptable.activityid
--and
tbattendance.attendancedate >= dateadd(dd,-7,getdate()) and tbattendance.attendancedate <= getdate()
group by convert(CHAR(10), tbattendance.attendancedate, 120)) x)
update ##temptable set meetings =
(select count(distinct convert(CHAR(10), tbattendance.attendancedate, 120)) as dayscount from tbteachertimelog
inner join tbattendance on tbattendance.activityid = tbteachertimelog.activityid and
convert(CHAR(10), tbattendance.attendancedate, 120) = convert(CHAR(10), tbteachertimelog.date, 120)
where teacherid = ##temptable.teacherid and tbteachertimelog.activityid = ##temptable.activityid)
select * from ##temptable
drop table ##temptable
The problem is with the following line in your subquery:
QUOTENAME(convert(CHAR(10), attendancedate, 120)) AS DATES
The QUOTENAME is required when you are creating the list of dates as the column headers but since you added this to your subquery your dates in the table appear:
DATES
[2013-11-22]
[2013-11-23]
[2013-11-24]
But you want the dates being returned inside your subquery should be without the brackets:
DATES
2013-11-22
2013-11-23
2013-11-24
The PIVOT function is looking for dates that match your data but since you have the dates surrounded with square brackets you don't get any matches, as a result you are returning zeros for everything.
Your columns don't match your data because of the bracket -- for example:
Header -- YourDate
2013-11-22 -- does not match [2013-11-22]
2013-11-23 -- does not match [2013-11-23]
2013-11-24 -- does not match [2013-11-24]
The query should be:
exec('
with data as
(
SELECT *
from
(
select distinct teachername as Teacher,
activityname AS Activity,
memberid as attendance,
convert(CHAR(10), attendancedate, 120) AS DATES
from tbteachertimelog
inner join tbteacher
on teacherid = tbteacher.id
inner join tbactivity
on tbactivity.id = tbteachertimelog.activityid
inner join tbattendance
on tbattendance.activityid = tbactivity.id
) p
PIVOT
(
count(attendance)
FOR DATES IN ('+#listdate+')
) AS pvt
)
select *
from data
')
I am trying to make a table like this:
ProductName | SalesByDate | TotalSalesUntilDate
A | 5 | 15
B | 10 | 30
C | 20 | 25
D | 18 | 43
SalesByDate means the number of product sold for each product on the input date and TotalSalesUntilDate indicates the number of product sold for each product from the first date of the month until the input date (example of input date: 17 March 2010)
I wrote this query using subquery:
select p.ProductName, A.SalesByDate,
(select(SUM(case when (pd.Date between '01' and #Date)
then s.SalesByDate else 0 end))
from Period pd
inner join Sales s on pd.TimeID = s.TimeID
full join Product p on s.ProductID = p.ProductID) as TotalSalesUntilDate
from Product p join
(select s.ProductID, pd.Date, s.SalesByDate
from Period pd join Sales s on pd.TimeID = s.TimeID) A on
p.ProductID = A.ProductID where #Date = A.Date
but I got the result:
ProductName | SalesByDate | TotalSalesUntilDate
A | 5 | 113
B | 10 | 113
C | 20 | 113
D | 18 | 113
which the TotalSalesUntilDate shows the number of product sold from the first date of the month until the input date but for all product without separation for each product.
So when I tried to change the query to like this (adding GROUP BY p.ProductID before "as TotalSalesUntilDate"):
select p.ProductName, A.SalesByDate,
(select(SUM(case when (pd.Date between '01' and #Date)
then s.SalesByDate else 0 end))
from Period pd
inner join Sales s on pd.TimeID = s.TimeID
full join Product p on s.ProductID = p.ProductID
group by p.ProductID) as TotalSalesUntilDate
from Product p join
(select s.ProductID, pd.Date, s.SalesByDate
from Period pd join Sales s on pd.TimeID = s.TimeID) A on
p.ProductID = A.ProductID where #Date = A.Date
and when I execute this query, I got this error message:
"Msg 512, Level 16, State 1, Procedure SalesMTDSubQuery, Line 7
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression."
Since I'm new in SQL and still learning, but I don't understand how to solve this. Any help will be appreciated. Thank you.
In the #Date variable we are storing the date:
SELECT DISTINCT PT.[ProductName]
,SUM(IIF(PD.[Date] = #Date, SL.[SalesByDate], 0))
,SUM(IIF(PD.[Date] BETWEEN '01' AND #Date, SL.[SalesByDate], 0))
FROM #Product PT
INNER JOIN #Sales SL
ON PT.[ProductID] = SL.[ProductID]
INNER JOIN #Period PD
ON SL.[TimeID] = PD.[TimeID]
GROUP BY PT.[ProductName]
Result:
Full code:
DECLARE #Period TABLE
(
[TimeID] TINYINT
,[Date] CHAR(2)
)
INSERT INTO #Period([TimeID], [Date])
VALUES (1,'01')
,(2,'02')
,(3,'03')
,(4,'04')
,(5,'05')
,(6,'06')
,(7,'07')
,(8,'08')
,(9,'09')
,(10,'10')
,(11,'11')
,(12,'12')
,(13,'13')
,(14,'14')
,(15,'15')
DECLARE #Product TABLE
(
[ProductID] TINYINT
,[ProductName] CHAR(1)
)
INSERT INTO #Product( [ProductID], [ProductName])
VALUES (1,'A')
,(2,'B')
,(3,'C')
,(4,'D')
DECLARE #Sales TABLE
(
[TimeID] TINYINT
,[ProductID] TINYINT
,[SalesByDate] TINYINT
)
INSERT INTO #Sales ([TimeID], [ProductID], [SalesByDate])
VALUES (1, 1, 10)
,(1, 4, 20)
,(7, 2, 10)
,(7, 3, 5)
,(15, 1, 5)
,(15, 2, 10)
,(15, 3, 15)
,(15, 4, 18)
,(19, 2, 15)
,(20, 3, 2)
,(22, NULL, 2)
,(1, 4, 5)
,(7, 2, 10)
,(15, 3, 5)
DECLARE #Date CHAR(2) = '15'
SELECT DISTINCT PT.[ProductName]
,SUM(IIF(PD.[Date] = #Date, SL.[SalesByDate], 0))
,SUM(IIF(PD.[Date] BETWEEN '01' AND #Date, SL.[SalesByDate], 0))
FROM #Product PT
INNER JOIN #Sales SL
ON PT.[ProductID] = SL.[ProductID]
INNER JOIN #Period PD
ON SL.[TimeID] = PD.[TimeID]
GROUP BY PT.[ProductName]
EDIT:
If you need to use sub-query, this is how your example can works:
SELECT PT.[ProductName]
,SUM(SL.[SalesByDate])
,DataSource.[TotalSalesByDate]
FROM #Product PT
INNER JOIN #Sales SL
ON PT.[ProductID] = SL.[ProductID]
INNER JOIN #Period PD
ON SL.[TimeID] = PD.[TimeID]
INNER JOIN
(
SELECT S.[ProductID]
,SUM(S.[SalesByDate]) AS [TotalSalesByDate]
FROM #Sales S
INNER JOIN #Period P
ON S.[TimeID] = P.[TimeID]
WHERE P.[Date] BETWEEN '01' AND #Date
GROUP BY S.[ProductID]
) AS DataSource
ON PT.[ProductID] = DataSource.[ProductID]
WHERE PD.[Date] = #Date
GROUP BY PT.[ProductName]
,DataSource.[TotalSalesByDate]
First, in the Table Period you must have dates, not '01','02' so you can use BETWEEN. Or you can use 1,2,3 ... but they have to be numbers.
So, we suppose that in table Table Period you have numbers for dates (I make this remark, because you use 01, instead of 1 which assumes string value. The query itself is relatively easy:
SELECT
p.ProductName,
SUM(CASE WHEN s.TimeID = 10 THEN s.SalesByDate ELSE 0 END) as SalesByDate,
SUM(CASE WHEN s.TimeID = 10 THEN 0 ELSE s.SalesByDate END) as TotalSalesUntilDate
FROM
Product p
INNER JOIN Salse s ON p.ProductID = s.ProductID
WHERE
s.TimeID BETWEEN 1 AND 10
GROUP BY p.ProductName;
You take Sales for each date. If this is a selected date then add sales to column SalesByDate, else add then to column TotalSalesUntilDate. You group by ProductName to calculate SUM. And select only dates which are in the desired period in WHERE clause. We assume that this query is started only for a specific month (because we use only date element - i.e. 1,2,... not month).
This will show only Products with sales. If you want to see all Products list use LEFT JOIN instead of INNER JOIN.