updating date by stored procedure - sql

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

Related

Procedure returning 0 instead of higher number

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;

Iterative Union ALL's

I have a large SQL Server 2012 Database which I am querying 3 tables to create a result set of 5 fields.
I want to repeat this query in a WHILE - loop and "UNION ALL" the result sets obtained in each loop. This iteration will be on a variable: #this_date which will increment over the past 6 years and stop at today's date.
At each iteration a different results set will be obtained by the SELECT.
So I am trying to code the Stored Procedure as follows:
Declare #the_date as Date,
#to_date as Date
-- I setup the above dates, #the_date being 6 years behind #to_date
-- Want to loop for each day over the 6-year period
WHILE (#the_date <= #to_date)
BEGIN
-- the basic select query looks like this
Select Table1.Field-1, Table2.Field-2 ...
FROM Table1
Inner Join Table2 ...
On ( ..etc.. )
-- the JOIN conditions are based on table.attributes which are compared with
-- #the_date to get a different result set each time
-- now move the date up by 1
DateAdd(Day, +1, #the_date)
-- want to concatenate the result sets
UNION ALL
END
The above gives me a syntax error:
Incorrect syntax near the keyword 'Union'.
Any ideas on a solution to my problem would be welcome
- thanks.
Don't use a UNION. You can't in a loop anyway. Instead store the results of each iteration in a temp table or a table variable and select from the temp table / table variable instead.
DECLARE #the_date as Date,
#to_date as Date
CREATE TABLE #t (Col1 VARCHAR(100))
WHILE (#the_date <= #to_date)
BEGIN
INSERT #t (Col1) SELECT ... etc
DateAdd(Day, +1, #the_date)
END
SELECT Col1 FROM #t
That said, if you provide some sample data and expected results we might be able to help you with a more efficient set-based solution. You should avoid iterative looping in RDBMS whenever possible.

How would I set the value of a variable to the results of a query in SQL?

I have a stored procedure that has two variables. They are #DateLeft and #DateRight. #DateLeft is the variable that I would like to set equal to the results of a query.#DateRight = GETDATE(). I have the following data:
EDIT 2: Added 'Distance' column
Date Code Distance **The values in the distance column are arbitrary and they are there for example's sake
11/23/2015 A 456
12/28/2015 B 2163
1/25/2016 C 203
4/30/2015 D 8921
My stored procedure is supposed to use #DateLeft and #DateRight to determine a date range that controls another calculation. These dates are the most recent dates that a particular event occurred. I am supposed to use the dates in the Date column as the #DateLeft value for each different code in the Code column. For example, the procedure should run and get 11/23/2015 as the value for #DateLeft for code A. It will then do its calculation and move on and get 12/28/2015 for code B, and so on. I don't know how to perform this calculation so that it doesn't have to run the whole procedure again to do its calculations with a different date for #DateLeft. My query for the end result looks something like this:
SELECT SUM(TraveledDistance) AS Distance, Code
FROM MyTable
WHERE
Time BETWEEN #DateLeft AND #DateRight
I would like to do something like this maybe (I'm open to suggestions, of course):
SET #DateLeft = Select Date From SampleTable
Group By Code --I know this doesn't work
Any help is appreciated.
EDIT: Description of procedure itself
The procedure takes the #DateLeft value (which, as it stands, is not a parameter) and uses it as a filter to calculate the distance traveled between that date and today's date (#DateRight). You can make up the calculation part if you want. I'm more concerned with the approach that I should take to set #DateLeft to each of the different dates for each of the codes, without having to repeat the procedure several times.
DECLARE #DateLeft DATE;
SELECT #DateLeft = [Date] From SampleTable Group By Code
You can set the variable value using this syntax.
Update based on OP's update:
The OP's updated request is not abundantly clear, but I believe a loop may do the trick.
DECLARE #DateLeft DATE;
DECLARE #Level INT = 0;
WHILE #Level < (SELECT COUNT(*) FROM SampleTable)
BEGIN
SELECT #DateLeft = [Date] From SampleTable Group By Code;
--do something with #DateLeft
SET #Level = #Level + 1;
END
If you need to do it like a loop you might need to look at SQL Server Cursor.
If you don't need a loop you can always select value to a variable like this:
declare #DateLeft as datetime;
SELECT #DateLeft = Date
From SampleTable
Group By Code;
Perhaps something like this is what you're looking for?:
select
(
/* calculation goes here */
select sum(m.TraveledDistance) as Distance
from MyTable m
/* correlate the subquery on t.Code and max t.Date */
where m.Code = t.Code and m.Time between max(t.Date) and getdate()
) as Calculation,
t.Code
from SampleTable t
group by t.Code
Your approach works as follows: SET #DateLeft = (Select Date From Sample Table Group By Code)

Avoiding while loops in SQL when a counter is required

I feel like this is a common problem, but it seems that none of the answers that I have found on SO or other sites seem to address the issue of a while loop with a counter.
Let's say that I am trying to write a stored procedure in SQL that will populate a user's timesheet by inserting a row for each day for the remainder of the month. If the #endMonth variable holds the last day of the month, then I know that I could easily write a while loop and do something along these lines:
WHILE #date <= #endMonth
BEGIN
//Do some action with the date, like an insert
SET #date = DATEADD(d, 1, #date) //increment the date by one day
END
However, looking at answers here and on other sites leads me to believe that it would be best to avoid using a while loop if at all possible.
So my question is this: is there a way I can implement a loop with a counter in SQL without using the WHILE structure? What technique would I use to go about converting a loop similar to the one I posted? Or with something like this, do I have to bite the bullet and just use a while loop?
As an aside, some of the following questions come close, but none of them seem to quite address the issue of needing a counter as a loop condition. Most of the answers seem to condemn using WHILE loops, but I can't seem to find a general purpose solution as to an alternative.
sql while loop with date counter
SQL Server 2008 Insert with WHILE LOOP (this one was close, but unfortunately for me it only works with an auto increment column)
I saw many examples of populating data.
First you create dates from starting to ending dates in cte and then you can insert it into table.
One of them is with cte:
DECLARE #StartDate DateTime = '2014-06-01'
DECLARE #EndDate DateTime = '2014-06-29'
;WITH populateDates (dates) AS (
SELECT #StartDate as dates
UNION ALL
SELECT DATEADD(d, 1, dates)
FROM populateDates
WHERE DATEADD(d, 1, dates)<=#EndDate
)
SELECT *
INTO dbo.SomeTable
FROM populateDates
You should try to look for on internet how to populate date in sql table
As a general case, you can increment values without using cursors by assigning values and incrementing the variable in the same select, like this:
DECLARE #i INT = 0
DECLARE #table TABLE
(
ID INT ,
testfield VARCHAR(5)
)
INSERT INTO #table
( testfield )
VALUES ( 'abcd'),
( 'efgh' ),
( 'ijkl' ),
( 'mnop' )
UPDATE #table
SET #I = ID = #i + 1
SELECT *
FROM #table
I used a sequence - create temporarily.
I needed to do my updates outside of script context, with plain SQL, sequence was the only "counter" I could come up with.

How to Update a Row Inside a While Loop In a Stored Procedure

I'm new to SQL and I'm coding a stored procedure but can't get it to do what I want.
In the stored procedure, I have a while loop running and not throwing any exemptions except my row I want to update in each line of the table doesn't update even though it is executing the query's inside the if statements in the while loop.
I would be much obliged if someone could explain to me what is going wrong here.
The stored procedure returns the table but the CommmissionRateID column has been unchanged.
I have attached one of the IF..ELSE statements that are causing the problems
IF (#SalePrice * 100) / #ListPrice > 50
BEGIN
SET #CommisionRateID = 3;
SELECT * FROM CarDetails
UPDATE CarDetails
SET CommissionRateID = #CommisionRateID
FROM CarDetails
WHERE CarID = (#i + 1)
END
Thanks,
First off, you are not declaring variables, you're actually declaring parameters which you are using like variables.
Apart from #CommisionRateID, every one of the parameters will have any original value overwritten before the original value could be used.Unless you need to pass a value into the SP and use it, then you should remove it from the parameter list and declare it in the body of the proc.
Regarding #CommisionRateID you never change the original value and it is used to determine whether or not you do anything at all. So I'm guessing that you are trying to use it as a criteria so that you only update records where the current value is NULL. In which case you don't need this parameter either
On the assumption that you want to set the commission rate for the cars based on the SalePrice & ListPrice, where there isn't a commission rate currently, I think that all your code can be replaced with the following:
CREATE PROC spAssignCommissionRate
AS
BEGIN
UPDATE CarDetails
SET CommissionRateID = CASE WHEN (SalePrice * 100) / ListPrice > 50 THEN 3
WHEN (SalePrice * 100) / ListPrice > 30 THEN 2
ELSE 1
END
WHERE CommissionRateID IS NULL
END
EDIT: IF anyone is wondering how the heck I inferred all this from the OPs code, I'm not actually psychic. Please take a look at the original version of the post.