"select" statement in stored Procedure is not working - sql-server

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

Related

Using date parameter in SQL Server CTE

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

Group by Datepart using total month daywise total orders

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

SQL Server : I need to pass a row value as a parameter to table function in a stored procedure

I want to create a stored procedure with a table-valued function as a column.
I want to use one of the other column values as the parameter for the function.
ALTER PROCEDURE [dbo].[AuditReportLeaseID]
#leaseID int
AS
BEGIN
SET NOCOUNT ON;
SELECT
a.assetID as Asset, a.Location,
CONVERT(VARCHAR, a.auditdate, 101) AS Date,
a.qtyaudit AS Qty,
c.classname AS Class, a.grade AS Grade,
a.serialnumber AS [S/N],
a.materialdescription AS Description, a.Notes,
(SELECT tf.AD
FROM fGetAuditDescrConcat(a.assetId) tf) AS AuditDescription
FROM
audit a
LEFT OUTER JOIN
ORDER_DETAILS od ON a.assetID = od.assetId
INNER JOIN
class c ON a.classid = c.classid
WHERE
a.classID = c.classID
AND a.leaseID = #leaseID
ORDER BY
class, grade, a.materialDescription
END
This procedure will return multiple rows and I want to use the value of the first column a.assetID (which is a varchar(64)) as the parameter to the fGetAuditDescrConcat function.
Is this possible?
Your question is unclear, but I take it you might be looking for something like this:
ALTER PROCEDURE [dbo].[AuditReportLeaseID]
#leaseID int
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM
(Select a.assetID
from audit a
left outer join ORDER_DETAILS od on a.assetID=od.assetId
inner join class c on a.classid=c.classid where a.classID = c.classID and a.leaseID = #leaseID
Order by class,grade,a.materialDescription
) a
CROSS APPLY fGetAuditDescrConcat(a.assetID)
END
If your given query returns error like Subquery returns more than one row;
Try the modified on as below:
ALTER PROCEDURE [dbo].[AuditReportLeaseID]
#leaseID int
AS
BEGIN
SET NOCOUNT ON;
SELECT
a.assetID as Asset, a.Location,
CONVERT(VARCHAR, a.auditdate, 101) AS Date,
a.qtyaudit AS Qty,
c.classname AS Class, a.grade AS Grade,
a.serialnumber AS [S/N],
a.materialdescription AS Description, a.Notes,
(SELECT TOP 1 tf.AD
FROM fGetAuditDescrConcat(a.assetId) tf) AS AuditDescription
FROM
audit a
LEFT OUTER JOIN
ORDER_DETAILS od ON a.assetID = od.assetId
INNER JOIN
class c ON a.classid = c.classid
WHERE
a.classID = c.classID
AND a.leaseID = #leaseID
ORDER BY
class, grade, a.materialDescription
END

SQL query stored procedure

Create a stored procedure that passes in the SalesOrderID as a parameter.
This stored procedure will return the SalesOrderID, Date of the transaction, shipping date, city and state. It is not running
Ans:
Create PROCEDURE proc_findProductInfo
#SalesOrderID int,
#SalesOrderOut int OUTPUT,
#OrderDate datetime OUTPUT,
#ShipDate datetime OUTPUT,
#CityState varchar(100) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET #SalesOrderOut = #SalesOrderID
SET #OrderDate = (SELECT OrderDate FROM SALES.SalesOrderHeader )
SET #ShipDate = (SELECT ShipDate FROM Sales.SalesOrderHeader)
SET #CityState = (SELECT a.City, st.Name
FROM Sales.SalesOrderHeader s
INNER JOIN Person.Address a ON s.ShipToAddressID = a.AddressID
INNER JOIN Person.StateProvince st ON s.TerritoryID = st.TerritoryID
WHERE SalesOrderID = #SalesOrderID)
END
DECLARE #OrderNum int, #Date datetime, #qty1 int, #Date1 datetime
EXEC proc_findProductInfo 63936,
#SalesOrderOut = #OrderNum OUTPUT,
#OrderDate = #Date OUTPUT,
#ShipDate = #date1,
#CityState = #qty1 output
SELECT #OrderNum, #date, #qty1, #Date1
Error Message:
Msg 116, Level 16, State 1, Procedure proc_findProductInfo, Line 25
Only one expression can be specified in the select list when the
subquery is not introduced with EXISTS
You're making this way harder than it needs to be:
Create PROCEDURE proc_findProductInfo
#SalesOrderID int
AS
BEGIN
SET NOCOUNT ON;
SELECT s.SalesOrderID, s.OrderDate, s.ShipDate, a.City,st.Name
FROM Sales.SalesOrderHeader s
INNER JOIN Person.Address a ON s.ShipToAddressID = a.AddressID
INNER JOIN Person.StateProvince st ON s.TerritoryID=st.TerritoryID
WHERE s.SalesOrderID = #SalesOrderID
END
I'm not even sure you need the StateProvince table here... the question probably allows you to trust the Address record.
It is complaining about the following
SET #CityState = (
SELECT a.City,st.Name
You are selecting both City and State Name and trying to assign it to a variable.
You either need to concatenate or coalesce them into them into a single output or alternatively use the below type of select to assign each one to a variable.
select
#var1 = field1,
#var2 = field2,
...
As below
SET #SalesOrderOut = #SalesOrderID
SELECT #OrderDate = s.OrderDate,
#ShipDate = s.ShipDate,
#CityState = CONCAT(a.City, ", ", st.Name)
FROM Sales.SalesOrderHeader s
inner JOIN Person.Address a
ON s.ShipToAddressID = a.AddressID
inner JOIN Person.StateProvince st
on s.TerritoryID=st.TerritoryID
WHERE SalesOrderID = #SalesOrderID

SQL Server : multiple join query optimization

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], ...))

Resources