here this is my stored procedure.. per day how many new orders and oldo rders are there in overall month..
i was declare date,totalorders and revenue..
result i'm getting only last day of the month that is 31st.. i want daywise orders count..
alter Procedure sp_NewandOld
(
#StartDate DATETIME,
#EndDate DATETIME
)
--[sp_NewandOld] '01/01/2015','01/31/2015'
AS
BEGIN
---New Customer Orders Breakup
Declare #NewCount int, #NewRevenue int, #NewDate nvarchar(50)
select #NewDate=(datepart(day,od.OrderDate)),
#NewCount= count(*),
#NewRevenue= SUM(CONVERT(decimal(18,2),od.TotalAmount)) from orderdetails od
inner join customer c on od.customerid=c.customerid
where Convert(Datetime,Convert(varchar(50),od.orderdate,101)) = Convert(Datetime,Convert(varchar(50),c.registereddate,101))
and Convert(Datetime,convert(varchar(50),od.orderdate,101)) between #StartDate and #EndDate
group by datepart(day, od.OrderDate)
Declare #OldCount int, #OldRevenue int, #OldDate nvarchar(50)
select #OldDate=(datepart(day,od.OrderDate)),
#OldCount= count(*),
#OldRevenue=SUM(CONVERT(decimal(18,2),od.TotalAmount)) from orderdetails od
inner join customer c on od.customerid=c.customerid
where Convert(Datetime,Convert(varchar(50),od.orderdate,101)) != Convert(Datetime,Convert(varchar(50),c.registereddate,101))
and Convert(Datetime,convert(varchar(50),od.orderdate,101)) between #StartDate and #EndDate
group by datepart(day, od.OrderDate)
select #NewDate,#NewCount,#OldCount,#NewRevenue,#OldRevenue
End
You select only first-row-values into a variables, and you need to get all. Change your query to this to get all data:
alter Procedure sp_NewandOld (
#StartDate DATETIME,
#EndDate DATETIME
)
AS
BEGIN
with [new] as (
select datepart(month,od.OrderDate) as newdatemonth,
datepart(day,od.OrderDate) as newdate,
count(*) as NewCount,
SUM(CONVERT(decimal(18,2),od.TotalAmount)) as NewRevenue
from orderdetails od
inner join customer c
on od.customerid=c.customerid
where Convert(Datetime,Convert(varchar(50),od.orderdate,101)) = Convert(Datetime,Convert(varchar(50),c.registereddate,101))
and Convert(Datetime,convert(varchar(50),od.orderdate,101)) between #StartDate and #EndDate
group by datepart(month,od.OrderDate), datepart(day, od.OrderDate)
), [old] as (
select datepart(month,od.OrderDate) as OldDateMonth,
datepart(day,od.OrderDate) as OldDate,
count(*) as OldCount,
SUM(CONVERT(decimal(18,2),od.TotalAmount)) as OldRevenue
from orderdetails od
inner join customer c
on od.customerid=c.customerid
where Convert(Datetime,Convert(varchar(50),od.orderdate,101)) != Convert(Datetime,Convert(varchar(50),c.registereddate,101))
and Convert(Datetime,convert(varchar(50),od.orderdate,101)) between #StartDate and #EndDate
group by datepart(month,od.OrderDate) , datepart(day, od.OrderDate)
)
select n.newdatemonth,
n.NewDate,
n.NewCount,
o.OldCount,
n.NewRevenue,
o.OldRevenue
from [new] n
inner join [old] o
on n.newdate = o.olddate and n.newdatemonth = o.OldDateMonth
End
Related
I'm trying to use a start and end date parameter in a T-SQL common table expression. I'm very new to SQL Server development and I'm unsure of what I'm missing in the query.
I can specify values for #startdate & #enddate and get correct results.
However, I'm trying to figure out how to make the two parameters open so a user can specify start and end date values. The query will be used in an SSRS report.
DECLARE #startdate Datetime,
#enddate Datetime;
SET #startdate = '2017-02-09';
SET #enddate = '2017-02-10';
WITH ManHours AS
(
SELECT DISTINCT
a.plant_name AS Plant, SUM(tc.total_hr) AS TotalHours
FROM
area AS a
INNER JOIN
tf_department AS dep ON a.plant_id = dep.plant_id
INNER JOIN
tf_timecard AS tc ON dep.department_id = tc.department_id
WHERE
tc.timecard_dt BETWEEN #startdate AND #enddate
AND tc.department_id IN (266, 453, ...endlessly long list of IDs......)
AND tc.hourtype_id = 1
GROUP BY
a.plant_name),
Tonnage AS
(
SELECT DISTINCT
a.plant_name AS Plant, SUM(tglt.postqty) AS TotalTonnage
FROM
area AS a
INNER JOIN
plantgl AS pgl ON a.plant_id = pgl.plant_id
INNER JOIN
tgltransaction AS tglt ON pgl.glacckey = tglt.glacctkey
WHERE
tglt.postdate BETWEEN #startdate AND #enddate
GROUP BY
a.plant_name
)
SELECT DISTINCT
ManHours.Plant,
SUM(TotalTonnage) as 'Production Tons' ,
SUM(TotalHours) as 'Man Hours',
TotalTonnage / TotalHours AS TonsPerManHour
FROM
ManHours
LEFT OUTER JOIN
Tonnage ON ManHours.Plant = tonnage.Plant
GROUP BY
ManHours.Plant, ManHours.TotalHours, Tonnage.TotalTonnage
Below is an example of a stored procedure you could use. In addition, I provided two alternatives to the "endlessly long list of IDs" that is specified in the CTE. In my opinion, it is optimal to pull this logic out of the query and place it at the beginning of the stored procedure. This will enable you, or others, to easily go back and modify this list if / when it changes. Even better, I provided a TABLE VARIABLE (#ListOfDeptIdsFromTable) that you can use to actually retrieve this data as opposed to hard-coding a string.
CREATE PROCEDURE Report
#startdate DATETIME,
#enddate DATETIME
AS
BEGIN
SET NOCOUNT ON;
DECLARE #ListOfDeptIds VARCHAR(MAX) = '266, 453, ...endlessly long list of IDs......';
DECLARE #ListOfDeptIdsFromTable TABLE
(
department_id INT
)
INSERT INTO #ListOfDeptIdsFromTable (department_id)
SELECT department_id
FROM -- Table here
WHERE -- Where credentials to retrieve the long list
WITH ManHours AS
(
SELECT DISTINCT
a.plant_name AS Plant, SUM(tc.total_hr) AS TotalHours
FROM
area AS a
INNER JOIN
tf_department AS dep ON a.plant_id = dep.plant_id
INNER JOIN
tf_timecard AS tc ON dep.department_id = tc.department_id
WHERE
tc.timecard_dt BETWEEN #startdate AND #enddate
AND tc.department_id IN (#ListOfDeptIds) -- or ... IN (SELECT department_id FROM #ListOfDeptIdsFromTable)
AND tc.hourtype_id = 1
GROUP BY
a.plant_name),
Tonnage AS
(
SELECT DISTINCT
a.plant_name AS Plant, SUM(tglt.postqty) AS TotalTonnage
FROM
area AS a
INNER JOIN
plantgl AS pgl ON a.plant_id = pgl.plant_id
INNER JOIN
tgltransaction AS tglt ON pgl.glacckey = tglt.glacctkey
WHERE
tglt.postdate BETWEEN #startdate AND #enddate
GROUP BY
a.plant_name
)
SELECT DISTINCT
ManHours.Plant,
SUM(TotalTonnage) as 'Production Tons' ,
SUM(TotalHours) as 'Man Hours',
TotalTonnage / TotalHours AS TonsPerManHour
FROM
ManHours
LEFT OUTER JOIN
Tonnage ON ManHours.Plant = tonnage.Plant
GROUP BY
ManHours.Plant, ManHours.TotalHours, Tonnage.TotalTonnage
END
GO
I have tried implementing a stored procedure for displaying the result from different tables by using inner join but my problem is select statement is not returning any result but its printing some of the values as messages.
alter proc EmployeeReport(#empid int)
as
begin
declare #inTime time(0)
declare #outTime time(0)
declare #fromDate date
declare #toDate date
set #inTime = (select CAST(InTime as time(0)) from Timelog where EmployeeId=#empid)
set #outTime = (select CAST(OutTime as time(0)) from Timelog where EmployeeId = #empid)
set #fromDate = (select cast (InTime as date) from Timelog where EmployeeId= #empid)
set #toDate = (select cast (outTime as date) from Timelog where EmployeeId= #empid)
select #fromDate as FromDate
,#toDate as ToDate
,c.Name as Client
,p.Name as Project
,#inTime as InTime
,#outTime as OutTime
,t.TotalTime
from Timelog t
inner join Employee e
on e.id = t.EmployeeId
inner join Project p
on p.Id = t.EmployeeProjectId
inner join Client c
on c.Id = p.ClientId
where t.EmployeeId = #empid
print #inTime
print #outTime
print #fromDate
print #toDate
end
I am attaching the output files what i am getting , please help me with this
Messeges getting printed:
No values returned or Selected:
Your initial declaration settings only select data from your TimeLog table, which clearly contains data. Because you are then inner joining from here to other tables, if those other tables have no data, nothing will be returned.
Either make sure that your Employee, Project and Client tables have data in them or change your joins to left instead of inner:
select #fromDate as FromDate
,#toDate as ToDate
,c.Name as Client
,p.Name as Project
,#inTime as InTime
,#outTime as OutTime
,t.TotalTime
from Timelog t
left join Employee e
on e.id = t.EmployeeId
left join Project p
on p.Id = t.EmployeeProjectId
left join Client c
on c.Id = p.ClientId
I have two specific dates.
lets say from 2014-04-04 To 2015-10-04.
I have a plan that says classes of Blah course will be on mon, wed and Fri.
Now I want to get the dates of each mon, wed and Fri from 2014-04-04 to 2015-10-04.
With a calendar table it is simple:
SELECT t.*
FROM dbo.TableName t
INNER JOIN CalendarTable c
ON t.DateColumn = c.Date
WHERE c.Date between '2014-04-04' AND '2015-10-04'
AND DATEPART(dw, c.Date) IN (1,3,5)
How to generate a calendar table (look for "Calendar table").
The standard reply to this by any seasoned SQL Server veteran, would be to create a calendar table. But all too often this is scoffed. So here's a slow and out-of-the-box method:
DECLARE #startDate DATE = '2014-04-04', #endDate DATE = '2015-10-04';
WITH CTE(N) AS (SELECT 1 FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))a(N)),
CTE2(N) AS (SELECT 1 FROM CTE x CROSS JOIN CTE y),
CTE3(N) AS (SELECT 1 FROM CTE2 x CROSS JOIN CTE2 y),
CTE4(N) AS (SELECT 1 FROM CTE3 x CROSS JOIN CTE3 y),
CTE5(N) AS (SELECT 1 FROM CTE4 x CROSS JOIN CTE4 y),
CTE6(N) AS (SELECT 0 UNION ALL
SELECT TOP (DATEDIFF(day,#startDate,#endDate))
ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM CTE5),
TALLY(N) AS (SELECT DATEADD(day, N, #startDate)
FROM CTE6
WHERE DATENAME(weekday,DATEADD(day, N, #startDate)) IN ('Monday','Tuesday','Wednesday'))
SELECT N
FROM TALLY
ORDER BY N;
You can use a Recursive CTE if you do not have numbers table. Something like this. Note that the DATEPART(weekday,Dates) IN(1,3,5) is based on your setting of SELECT ##DATEFIRST.
For example If ##DATEFIRST is 1 then use DATEPART(weekday,Dates) IN(1,3,5)
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-04-04'
SET #EndDate = '2015-10-04'
;WITH CTE AS
(
SELECT #StartDate Dates
UNION ALL SELECT DATEADD(d,1,Dates) FROM CTE WHERE DATEADD(d,1,Dates) <=#EndDate
)
SELECT Dates,DATENAME(weekday,Dates) FROM CTE
WHERE DATEPART(weekday,Dates) IN(1,3,5)
OPTION (MAXRECURSION 0);
GO
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-04-04'
SET #EndDate = '2015-10-04'
;WITH CTE AS
(
SELECT #StartDate Dates
UNION ALL SELECT DATEADD(d,1,Dates) FROM CTE WHERE DATEADD(d,1,Dates) <=#EndDate
)
SELECT Dates,DATENAME(weekday,Dates) FROM CTE
WHERE DATEPART(weekday,Dates) IN(1,3,5)
OPTION (MAXRECURSION 0);
GO
--- thanks to #ughai
I've comeup with another way to do this.
this query will not only Show the dates in between but also it will compare the dates u want to compare with.
Q.Dates Comparison
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-12-22'
SET #EndDate = '2015-02-13'
drop table #TabCourseDetailID
SELECT ROW_NUMBER() OVER(ORDER BY CourseDetailID asc) AS Row,
CourseDetailID
into #TabCourseDetailID
from coursedetail
where UnitType='T' and courseID =1
Declare #counter as int
Declare #CourseDetailID varchar(500)
set #counter = 0
Declare #TempTable Table (FirstValue datetime,LastValue int)
while #StartDate <= #EndDate
begin
If DATEPART(WeekDay,#StartDate) IN (2,4,6)
begin
Set #Counter = #counter+1
Select #CoursedetailId=CoursedetailId
from #TabCourseDetailID
where row=#counter
insert into #TempTable (FirstValue,LastValue)
values (#StartDate,#CoursedetailId)
end
set #StartDate =DATEADD(d,1,#StartDate)
end
select t.LastValue,
t.FirstValue,
bp.conductedDate
from batchprogress bp
Join #TempTable t on (t.LastValue=bp.CoursedetailID)
where CourseID =1 and batchID =5
order by t.lastvalue
I've just started with Microsoft SQL Server and I'm facing a problem, which I believe it is an sql optimization issue. Could you please take a look (see below) and give me your feedback.
I have two tables defined as follows:
floatTable (DateAndTime datetime2(7),
TagIndex smallint,
Val float)
stringTable (DateAndTime datetime2(7),
TagIndex smallint,
Val float)
The SQL query which I have used to get the RESULT is (don't laugh):
DECLARE #startDate DATETIME, #endDate DATETIME
SET #startDate = '20130312 9:00:00'
SET #endDate = '20130313 9:00:00'
USE TensionDB
SELECT t1.DateAndTime, t1.Val AS Winch_1,t2.Val AS Winch_2, t3.Val AS Winch_3, t4.Val AS Winch_4, t5.Val AS Winch_5,
t6.Val AS Winch_6, t7.Val AS Winch_7, t8.Val AS Winch_8, t9.Val AS Latitude, t10.Val AS Longitude
FROM
((SELECT DISTINCT DateAndTime ,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 0)t1
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE ( DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 1)t2
ON t2.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 2)t3
ON t3.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 3)t4
ON t4.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 4)t5
ON t5.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 5)t6
ON t6.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 6)t7
ON t7.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 7)t8
ON t8.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime, Val FROM dbo.StringTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 8)t9
ON t9.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime, Val FROM dbo.StringTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 9)t10
ON t10.DateAndTime = t1.DateAndTime)
PROBLEM: The big problem is that even if I get the correct result, the query gets very slow for large amount of data. I'm pretty sure that there is another way to write the query, but for the moment I don't have any other idea.
Could you give me a hint please? Appreciate any help from your side.
Thank you in advance
#Kiril and #Patrick,
Using your hints and ideas I have re-wrote my original query using pivot table.
Unfortunately, I still have to use INNER JOIN, as the values(Val) in the stringTable are strings and values(Val) in floatTable are floats. To be honest, I have to perform more tests with both queries, as I can't see a real improvement (time wise), using pivot table; apart from the length of the query. One last thing, I have embedded the query in a stored procedure. Please find below the "final" code:
-- ================================================
-- Template generated from Template Explorer using:
-- Create Procedure (New Menu).SQL
--
-- Use the Specify Values for Template Parameters
-- command (Ctrl-Shift-M) to fill in the parameter
-- values below.
--
-- This block of comments will not be included in
-- the definition of the procedure.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: xxxx
-- Create date: xxxx
-- Description: retrieves tension data
-- =============================================
CREATE PROCEDURE getTension
-- Add the parameters for the stored procedure here
#startDate datetime = NULL,
#endDate datetime = NULL
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT distinct pvt.DateAndTime
, pvt.[0] AS Winch_1
, pvt.[1] AS Winch_2
, pvt.[2] AS Winch_3
, pvt.[3] AS Winch_4
, pvt.[4] AS Winch_5
, pvt.[5] AS Winch_6
, pvt.[6] AS Winch_7
, pvt.[7] AS Winch_8
, st.Val AS Longitude
, st1.Val AS Latitude
FROM FloatTable
PIVOT
(MAX(Val)
FOR TagIndex in ([0],[1],[2],[3],[4],[5],[6],[7])
) as pvt
inner join StringTable st on st.DateAndTime = pvt.DateAndTime and st.TagIndex = 8
inner join StringTable st1 on st1.DateAndTime = pvt.DateAndTime and st1.TagIndex = 9
Where (pvt.DateAndTime between #startDate and #endDate)
ORDER BY DateAndTime
END
GO
Thanks again for your guidance
I suppose that using pivot table is going to be more efficient:
DECLARE #startDate DATETIME, #endDate DATETIME
SET #startDate = '20130312 9:00:00'
SET #endDate = '20130313 9:00:00'
SELECT st.DateAndTime
, pvt.0 AS Winch_1
, pvt.1 AS Winch_2
, pvt.2 AS Winch_3
, pvt.3 AS Winch_4
, pvt.4 AS Winch_5
, pvt.5 AS Winch_6
, pvt.6 AS Winch_7
, pvt.7 AS Winch_8
, pvt.8 AS Latitude
, pvt.9 AS Longitude
FROM StringTable st
INNER JOIN FloatTable ft on st.DateandTime=ft.DateandTime
pivot
( MAX(Val) for [TagIndex] in ([0], [1], [2], [3], [4], [5], [6], [7], [8], [9])
order by [st.DateAndTime]
)pvt
I haven't tested it so you may have to tweak it a bit, in order to make it work.
Start putting DateAndTime and TagIndex in an index. That would make a difference.
On the other hand, your query could get a lot faster if you wouldn't need the repeating inner joins.
Can you replace the distinct by a single group by and use min or max?
Another option is using pivot tables.
Like this:
select *
from FloatTable
pivot (min(DateAndTime) x, min(Val) y in ([1],[2],[3], ...))
I am trying to combine two query's together but I'm having trouble as it is a datetime column. right now I have a query that finds all the users + there slowest and fastest "Segment" time but I also need to find the avg segment time below are the two query's I am using right now which work but I need it to be in one query for a report I am making.
Thanks
Thomas James
DECLARE
#vnuID int = 1212,
#StartDate DateTime = '30/10/2013',
#EndDate DateTime = '26/11/2013'
SELECT DISTINCT usrFullName, MIN(CAST(tblTrace.trFinish - tblTrace.trStart AS TIME)) AS FastestUserSegmentTime,
MAX(CAST(tblTrace.trFinish - tblTrace.trStart AS TIME)) AS SlowestUserSegmentTime
FROM tblTrace
INNER JOIN tblUsers ON usrID = tr_usrID
WHERE tr_vnuID = #vnuID AND trFinish IS NOT NULL AND tr_usrID IS NOT NULL AND trObjectType LIKE 'Segment%'
AND trStart BETWEEN #StartDate AND #EndDate
GROUP BY usrFullName
SELECT AVG(TotalTime) AS AvgUserSegmentTime
FROM (SELECT DateDiff(SECOND, tblTrace.trStart , tblTrace.trFinish) as 'TotalTime'
FROM tblTrace
WHERE tblTrace.trFinish IS NOT NULL AND tblTrace.trObjectType LIKE 'Segment%' AND tblTrace.tr_vnuID = #vnuID
AND tblTrace.trStart BETWEEN #StartDate AND #EndDate ) as SubQuery
Functionally (i.e. without optimization) you could use something like this:
DECLARE
#vnuID int = 1212,
#StartDate DateTime = '30/10/2013',
#EndDate DateTime = '26/11/2013'
SELECT usrFullName, FastestUserSegmentTime, SlowestUserSegmentTime,
(SELECT AVG(DateDiff(SECOND, tblTrace.trStart , tblTrace.trFinish))
FROM tblTrace
WHERE tblTrace.trFinish IS NOT NULL AND tblTrace.trObjectType LIKE 'Segment%' AND tblTrace.tr_vnuID = #vnuID
AND tblTrace.trStart BETWEEN #StartDate AND #EndDate) as AvgUserSegmentTime
FROM (
SELECT usrFullName,
MIN(CAST(tblTrace.trFinish - tblTrace.trStart AS TIME)) AS FastestUserSegmentTime,
MAX(CAST(tblTrace.trFinish - tblTrace.trStart AS TIME)) AS SlowestUserSegmentTime
FROM tblTrace
INNER JOIN tblUsers ON usrID = tr_usrID
WHERE tr_vnuID = #vnuID AND trFinish IS NOT NULL AND tr_usrID IS NOT NULL AND trObjectType LIKE 'Segment%'
AND trStart BETWEEN #StartDate AND #EndDate
GROUP BY usrFullName
) coreData
However, I would assume that you would want tr_usrID not to be null in all cases? In which case you could just use this:
SELECT usrFullName,
CONVERT(TIME, DATEADD(s, MIN(SegmentTime))) as FastestUserSegmentTime,
CONVERT(TIME, DATEADD(s, MAX(SegmentTime))) as SlowestUserSegmentTime,
AVG(SegmentTime) as AvgUserSegmentTime
FROM (
SELECT usrFullName,
DateDiff(SECOND, tblTrace.trStart, tblTrace.trFinish) as SegmentTime
FROM tblTrace INNER JOIN
tblUsers
ON usrID = tr_usrID
WHERE tr_vnuID = #vnuID
AND trFinish IS NOT NULL
AND tr_usrID IS NOT NULL
AND trObjectType LIKE 'Segment%'
AND trStart BETWEEN #StartDate AND #EndDate
) coreData