Procedure returning 0 instead of higher number - sql

I have the following procedure to retrieve some data, based by the year, which is input by the user. However, I always get a 0 back. I'm still fairly new to SQL, but this seemed like it should work
Create PROCEDURE [dbo].[Yearly]
#year int
AS
BEGIN
DECLARE #yearly Datetime
DECLARE #summ int
SELECT #summ = SUM([dbo].[Out].[OutPcs]), #yearly = [dbo].[Out].[DateTime]
FROM [dbo].[Out]
WHERE YEAR(#yearly) = #year
GROUP BY [Out].[DateTime]
END;
Should I have used nested select statements? I suspect something is wrong in that part of the procedure.

You have DECLARE #yearly Datetime.
You attempt to set it in SELECT ... #yearly = Out.Datetime FROM Out, but then you have this WHERE statement: YEAR(#yearly) = #year
This returns nothing since #yearly is NULL when called by YEAR()
This makes the statement equivalent to WHERE NULL = 2018
Which will never be true.
To fix this, you need to set yearly before calling it in your WHERE clause or use something else there.
It looks like you want to use YEAR(Dbo.Out.Datetime) instead there
Since it looks like you're new to SQL I will add some extra explanation. This is an oversimplification.
Most programming languages run top to bottom. Executing the line1 first, line2 second, line3 third, and so on. SQL does not do this.
The command SELECT Name FROM Employee WHERE EmpID = 1 Runs in the following order.
First - FROM Employee --> Load the Employee table
Second - WHERE EmpID = 1 --> Scan Employee for the records where EmpID = 1
Third - SELECT Name --> Display the `Name` field of the records I found.
Your command looks like this to the SQL compiler
First - FROM dbo.Out --> Load Out table
Second - WHERE YEAR(#yearly) = #year --> Scan for records that meet this req.
Third - SELECT ... #yearly = dbo.Out.Datetime --> Set #yearly to the [Datetime] field associated to the record(s) I found.
Note that if your statement had returned multiple records, then SQL would have tried to set your 1-dimensional variable to an array of values. It would fail and give you something like
Too many records returned. Have me only return 1 record.

Why your code is not working is well explained by #Edward
Here is a working code:
Create PROCEDURE [dbo].[Yearly]
#year int
AS
BEGIN
SELECT SUM([dbo].[Out].[OutPcs])
FROM [dbo].[Out]
WHERE YEAR([dbo].[Out].[DateTime]) = #year
END;

You forgot to return "summ":
And #yearly var is not necessary.
Group by Year is not necessary too.
Create PROCEDURE [dbo].[Yearly]
#year int
AS
BEGIN
DECLARE #summ int
SELECT #summ = SUM([dbo].[Out].[OutPcs])
FROM [dbo].[Out]
WHERE YEAR([dbo].[Out].[DateTime]) = #year
Return #summ
END;

Related

SQL Server Method to Put Top 10 SELECTED rows (all columns) of a joined table into an Array or a variable table

I am struggling to figure out how to get this stored procedure to return all appointments for the userId (this is the only input required). Right now it is only returning one appointment. I want it to return all 5 attributes (appointment_id, host_name, visit_start, visit_end, and visit_location) for each appointment associated with the userId, with each appointment separated by {}. So if a visitor has 5 appointments for the day, I want all 5 appointments to be returned (along with the 5 appointment attributes), with each separate appointment enclosed in {}. I also want to take care of the case where a userId has no appointments associated with it. This code works perfectly, but, like I said only returns 1 appointment instead of all that are associated with the userId. I feel like I need an to make an appointment array although I don't believe arrays are part of SQL server. I might need a variable table but i am not sure how to implement one. I am open to any suggestions.
CREATE PROCEDURE [dbo].[GetMeetings]
(
#userId BIGINT,
#appointmentId BIGINT OUTPUT,
#hostName NVARCHAR(101) OUTPUT,
#startTime DATETIMEOFFSET(7) OUTPUT,
#endTime DATETIMEOFFSET(7) OUTPUT,
#location NVARCHAR(100) OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
SELECT TOP 10
#appointmentId = appointment_id,
#hostName = host_name,
#startTime = visit_start,
#endtime = visit_end,
#location = visit_location
FROM
dbo.reg_visits v1 INNER JOIN dbo.reg_visitors v2 on v1.reg_visit_id = v2.reg_visits_reg_visit_id
WHERE
v2.reg_visits_reg_visit_id IN
(SELECT TOP 10
reg_visits_reg_visit_id AS id
FROM
dbo.reg_visitors
WHERE visitor_profile_visitor_id = #userId
ORDER BY
reg_visitors_id DESC)
AND v1.visit_start > GETDATE() ORDER BY v1.reg_visit_id desc
END
Your select statement should just be
CREATE PROCEDURE [dbo].[GetMeetings]
(
#userId BIGINT
)
AS
BEGIN
SET NOCOUNT ON
SELECT TOP 10
appointment_id,
host_name,
visit_start,
visit_end,
visit_location
We want to return this as a result set and not as an out parameter. OUTPUT parameters can really only have one value, so that's why you are getting only one appointment back, and it is probably always the last of the 10 rows that you are expecting. So get rid of all the OUTPUT parameters too and just send in the userid.

SQL Update Stored Procedure involving Subqueries

I have a few table's in my DB.
I am trying to update the rota table using a SQL stored procedure. I want the user to be able to type in, for example;
Name: Adam Brookes
Shift: Middle Day
On Call: Secondary
and using a subquery have it look up the id's of those and place them into the rota table. At the moment I am testing in Postman where I can define the 'date' and 'datekey' manually.
My Stored Procedure currently looks like this;
ALTER PROCEDURE [dbo].[RotaUpdateItems]
#date_key int,
#date date,
#user_id varchar(max),
#shift_type_id int,
#type_call_id int
AS
BEGIN
SET NOCOUNT ON;
UPDATE rota
SET date = #date,
user_id = (
SELECT user_id
FROM staff s
WHERE s.first_name LIKE 'ABC%'
),
shift_type_id = (
SELECT shift_type_id
FROM shifts h
WHERE h.shift_type LIKE 'ABC%'
),
type_call_id = (
SELECT type_call_id
FROM on_call c
WHERE c.type_of_call LIKE 'ABC%')
WHERE date_key = #date_key
END
I have referenced this question to get the LIKE 'ABC%' code to see if that would help convert "Primary" into '1', but this did not fully answer my question
I also researched this answer from John to see if a join is necessary when running an update query but this did not fully answer my question.

Make Stored Procedure return a VarChar

First of all I am new to SQL, yet I have a great Java background. My problem is that I am trying to make this procedure return a varchar, yet it is not letting me.
I tried using the RETURN statement (I now know it only returns INTS) and the SELECT statement, but for some reason it continues to return an int.
Here is my code
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE get_TopGuildLeader
AS
--Variables
DECLARE #LeaderUID VARCHAR(20);
DECLARE #GuildID INT
DECLARE #MaxPoints INT
--Selecting Leader
SET #MaxPoints = (SELECT MAX(GuildPoint)
FROM PS_GameData.dbo._GuildRankPoint)
SET #GuildID = (SELECT GuildID
FROM PS_GameData.dbo._GuildRankPoint
WHERE GuildPoint = #MaxPoints);
SET #LeaderUID = (SELECT MasterName
FROM PS_GameData.dbo._GuildsBack
WHERE GuildID = #GuildID);
--Return Leader Name
SELECT #LeaderUID;
You need to return data using OUTPUT parameters instead of SELECT.
Refer link on how to achieve this:
https://technet.microsoft.com/en-us/library/ms187004(v=sql.105).aspx
Hope this helps!
You can use an output parameter. However, be careful with your SQL query. I'm not familiar with your data model, but it looks like your query could result in a run time error. For example, is it possible that there could be more than one GuildID with the same number of GuildPoints? If so, the second query in your stored procedure will fail and return a message like below.
Msg 512, Level 16, State 1, Line 2
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, , >= or when the subquery is used as an expression.
There are many ways to approach and protect against that potential issue. Below is an example of how to consolidate the logic down to one compact query and guarantee that there will always be one row returned.
create proc dbo.GetTopGuildLeader
#LeaderId varchar(20) output
as
set #LeaderId = (
select top 1 gb.MasterName
from PS_GameData.dbo._GuildRankPoint grp
join PS_GameData.dbo._GuildsBack gb
on grp.GuildID = gb.GuildID
order by GuildPoint);
go
Hope this helps.

updating date by stored procedure

I have a problem!
My task is to count the age of books in my library database. After that call some books as too rare, some rare , and usual using value column.
My library table ( ... , age- date , value- date)
notice: "age" - is incorrect definition of a column, it would be better to say "year of publication". Actually my task is to find age!
So, I do this, and my value column does not change :(
create procedure foo
as
declare #bookdate date,
#currentdate date,
#diff int
set #currentdate = GETDATE()
select #bookdate = age from books
select #diff = DATEDIFF (yyyy , #bookdate , #currentdate )
Version #1:
UPDATE books SET value = DATEADD(year,#diff, age)
Version #2:
UPDATE books SET value = #diff
P.S. sorry for any mistakes I made, it is my first step in sql, programming at all, and asking for help in English!
To me it sounds like you want something like this (I'm assuming you're using SQL Server as you've used the GETDATE() function):
CREATE PROCEDURE foo
AS
BEGIN
SELECT *
,DATEDIFF(yyyy,age,GETDATE()) AS YearsSincePublication
,CASE WHEN DATEDIFF(yyyy,age,GETDATE()) > 200 THEN 'Too rare'
WHEN DATEDIFF(yyyy,age,GETDATE()) > 100 THEN 'Rare'
ELSE 'Usual'
END AS Value
FROM books
END
Working form the top:
* means all columns from all tables
The datediff is working out the number of years since the publication and the AS bit names the resulting column (gives it an alias).
The CASE Statement is a way to test statements (if a equals b, do c). The first statement checks to see iff the book is more than 200 years old and if so, writes 'Too rare', the second line checks for more than 100 years, otherwise it writes 'usual'. Again, the AS is used to label the column to Value.
Finally the table we want our data from is specified, Books.
To run the stored procedure once you have created it is simply:
EXEC foo

SQL - Counting Returned Records

I'm building a stored procedure. This stored procedure needs to insert a record if a record with a specific value does not exist. If the value does exist, I need to update the record. The problem I'm having is determining if a record with the given value exists or not. I am using the following code:
DECLARE #record1ID as char(36)
SET #record1ID = (SELECT TOP 1 ID FROM Person WHERE [Role]='Manager')
DECLARE #record2ID as char(36)
SET #record2ID = (SELECT TOP 1 d.ID FROM Department d WHERE d.[ManagerID]=#record1ID)
-- If #record2ID is set update record, otherwise add record
-- how do I setup this if/else statement?
Thank you!
If this were a SQL Server as it looks like, you could do a count like this:
declare #rec_counter as int
set #rec_counter = 0
select #rec_counter = count(*) FROM Department d WHERE d.[ManagerID]=#record1
if (#rec_counter > 0)
begin
-- do whatever here
end
IF (EXISTS YOUR_SELECT)
BEGIN ...
or
IF (#record2ID IS NULL)
BEGIN ...
or use select count(*) instead of selecting a value