Issues with SQL Max function: "Incorrect syntax new the keyword 'SELECT' " - sql

I'm trying to write a stored procedure to return the maximum value of a column + 1 but for some reason it doesn't want to work.
DECLARE #ID int;
SET #ID = SELECT MAX(ID) + 1 FROM tbl;
I can't for the life of me see what is wrong.
It gives me the error of:
incorrect syntax new the keyword 'SELECT'

No need for SET. Select value directly:
DECLARE #ID int;
SELECT #ID = MAX(ID) + 1 FROM tbl;

Use parentheses ( ... ):
DECLARE #ID int;
SET #ID = (SELECT MAX(ID) + 1 FROM tbl);
or SELECT as suggested by Giorgi. SET is the ANSI standard way of assigning values to variables, SELECT is not. Apart from that using SELECT to assign values to variables is fine, it allows even multiple assignments with one SELECT.
But in general your query seems to be a race condition. Use an IDENTITY column if you want to autoincrement a value. Auto increment primary key in SQL Server Management Studio 2012

You need to consider a scenario when there is no value in the table and MAX returns NULL.
DECLARE #ID int;
SELECT #ID = ISNULL(MAX(ID) , 0) + 1 FROM tbl;
Other adding 1 to null will always yield null.

DECLARE #ID int;
SET #ID = (SELECT MAX(ID) + 1 FROM tbl);
parentheses operator ()
for more information
https://msdn.microsoft.com/en-us/library/ms190276.aspx

Related

SQL Server run SELECT for each in list

I won't be surprised if SQL just doesn't work this way at all, but:
If we run two SELECT statements in a query, we get a split "Results" pane. I'm wondering if I can add variables to a list, and then have the number of result pane splits match the length of that list.
If I were to mix languages:
id_list = [26275, 54374, 84567]
for i in id_list:
SELECT * FROM table WHERE id = i
I'm just trying to easily compare results of a query while keeping distinct groups, with a changing number of variables. Since loops never seem to be the answer in SQL, I'd be just as happy inserting something like a blank line or horizontal rule, etc. Not sure if that's possible either though...
There is no concept of "lists" (as a separate data structure) in T-SQL. Does this do what you want?
SELECT *
FROM table
WHERE id IN (26275, 54374, 84567);
declare #i int = 0;
declare #Id int;
declare #Ids table (Id int);
insert #Ids select Id from (values (26275), (54374), (84567)) t(Id);
-- OR: insert #Ids select * from string_split('26275, 54374, 84567', ',');
declare #Count int = (select count(*) from #Ids);
while #i < #Count
begin
select #Id = Id, #i = #i + 1
from #Ids order by Id
offset #i rows fetch next 1 rows only;
select * from dbo.MyTable where Id = #Id;
end
You can use UNION ALL:
SELECT * FROM table WHERE id = 26275
UNION ALL
SELECT * FROM table WHERE id = 54374
UNION ALL
SELECT * FROM table WHERE id = 84567

HSQL SELECT Statement Not working

I am new in HSQL. Tried a Procedure like below;
CREATE PROCEDURE GetData(ObjectId VARCHAR(36)) READS SQL DATA
DYNAMIC RESULT SETS 1
BEGIN ATOMIC
DECLARE MaxVal NUMERIC(19,2);
DECLARE MinVal NUMERIC(19,2);
DECLARE BiggestObjectName VARCHAR(50);
DECLARE SmallestObjectName VARCHAR(50);
SET MaxVal = (SELECT MAX(HeightValue) FROM ObjectData WHERE ObjectId=ObjectId);
SET MinVal = (SELECT MIN(HeightValue) FROM ObjectData WHERE ObjectId=ObjectId);
SET BiggestObjectName = (SELECT ObjectName FROM ObjectData WHERE ObjectId=ObjectId AND HeightValue=MaxVal);
SET SmallestObjectName = (SELECT ObjectName FROM ObjectData WHERE ObjectId=ObjectId AND HeightValue=MinVal);
if MaxVal IS NOT NULL THEN
DECLARE result CURSOR WITH RETURN FOR
SELECT MaxVal AS MaximumHeight, MinVal AS MinimumHeight, BiggestObjectName AS LargestDisplayCaseName, SmallestObjectName AS SmallestDisplayCaseName FOR READ ONLY;
OPEN result;
END
But i get error;
Caused by: java.sql.SQLSyntaxErrorException: unexpected token: ; required: INTO
Is it not the correct syntax?
Any help is appreciated :)
There are several things wrong with your stored procedure. For one I don't think you can declare a cursor as part of an IF statement.
Assignment of a variable needs to be either using select ... into or you need to put the select statement between parentheses:
SET MaxVal = (SELECT MAX(HeightValue) FROM ObjectData WHERE ObjectId=ObjectId);
SET ObjectName = (SELECT ObjectName FROM ObjectData WHERE ObjectId=ObjectId AND HeightValue=MaxVal);
or
SELECT MAX(HeightValue)
into maxval
FROM ObjectData
WHERE ObjectId=ObjectId;
You also can't use = or <> to compare NULL values. if MaxVal != NULL THEN needs to be
if maxval is not null then
...
end if; --<< you also forgot the `end if`
You also can't use a SELECT statement without a FROM clause, and I don't think you can define a cursor that only selects values from variables in HSQLDB.
But don't need the intermediate selects anyway, you can do that in a single select:
CREATE PROCEDURE GetData(ObjectId VARCHAR(36)) READS SQL DATA
DYNAMIC RESULT SETS 1
BEGIN ATOMIC
DECLARE result CURSOR FOR
select o1.heightvalue as maximumheight, o1.objectname as displaycasename
from objectdata o1
where objectid = 'one'
and heightvalue = (select max(heightvalue)
from objectdata o2
where o2.objectid = o1.objectid);
OPEN result;
END;
You are not using the correct syntax to create the procedure. According to the syntax you have to put the value(s) selected from table into a local variable(s). Follow the following example.
CREATE PROCEDURE get_customer(IN id INT, OUT firstname VARCHAR(50), OUT lastname VARCHAR(50))
READS SQL DATA
BEGIN ATOMIC
-- this statement uses the id to get firstname and lastname
SELECT first_name, last_name INTO firstname, lastname FROM customers WHERE cust_id = id;
END
I hope it'll help you.

Finding MAX value of data type Varchar

Firstly I have a table tblSample with ID as column of datatype INT. To auto generate ID for every transaction, I created a stored procedure:
DECLARE #Id INT
SELECT #Id = MAX(Id)
FROM tblSample
IF #Id IS NULL
BEGIN
SELECT 0 as Id
END
ELSE
SELECT MAX(Id) as ID FROM tblSample
Here as you observe if ID has no rows MAX(Id)=0 then return 0 or else return MAX(ID) value so that next insertion will be greater than max(ID).
That's fine but now I had column ID with datatype VARCHAR I have to do similar operation how can I that?
The code looks fine so it should work with VARCHAR also but my suggestion is to use storage variable also with same datatype so it won't get conflicted anywhere in the operation:
DECLARE #Id VARCHAR(10)
I think you could use MAX(CAST(varcharcolumn AS Int))
DECLARE #Id INT
SELECT #Id=MAX(Id) FROM tblSample
IF #Id IS NULL
BEGIN
SELECT 'Your_VarCharValue' + CAST(0 AS VARCHAR) as Id
END
ELSE
SELECT 'Your_VarCharValue' + CAST(MAX(Id) AS VARCHAR) as ID FROM tblSample

Find a column where the identity column is breaking

I have a table, e.g.
cust_ord_key
1
2
3
4
5
7
9
How do I write a query to find out if the numbers are in sequence and not breaking anywhere?
In SQL Server:
SELECT SeqID AS MissingSeqID
FROM (SELECT ROW_NUMBER() OVER (ORDER BY column_id) SeqID from sys.columns) LkUp
LEFT JOIN dbo.TestData t ON t.ID = LkUp.SeqID
You may do something like:
DECLARE #RESULT int;
SET #RESULT = 0;
DECLARE #FIRST_ID int;
DECLARE #LAST_ID int;
DECLARE #THIS_VALUE int;
DECLARE #NEXT_VALUE int;
SELECT #FIRST_ID = min(ID), #LAST_ID = max(ID) from table_name;
WHILE(#FIRST_ID <= #LAST_ID)
BEGIN
SELECT #THIS_VALUE = your_field_with_keys from table_name where ID = #FIRST_ID;
SELECT #NEXT_VALUE = your_field_with_keys from table_name where ID = (#FIRST_ID + 1);
if #THIS_VALUE > #NEXT_VALUE
SET #RESULT = #FIRST_ID;
--break your query here or do anything else
SET #FIRST_ID = #FIRST_ID + 1;
END
What does this query do? We declare #RESULT variable for taking an ID of key, where you key is breaking. #FIRST_ID and #LAST_ID are the minimal and maximal IDs from your table, we will use them later. #THIS_VALUE and #NEXT_VALUE are two variables for two keys to be compared.
Then we execute loop over our IDs. Then setting up #THIS_VALUE and #NEXT_VALUE with corresponding keys (this and the next). If #THIS_VALUE more than #NEXT_VALUE, it means that the key is breaking here (if previous key is more than next key), and we take the ID of element, where key is broken. And there you may stop your query or do some required logic.
This is not perfect, but definitely does the job, and is universal across all DB engines.
SELECT t1.id FROM myTable t1
LEFT JOIN myTable t2 ON t1.id+1 = t2.id
WHERE t2.id IS NULL
When the identity doesn't break anywhere, this will only return the last entry. You can compensate for that with a procedural language, by first getting the MAX(ID) adding that to the WHERE clause like this:
WHERE t2.id IS NULL AND t1.id<>5643
where 5643 is the max id (either a variable introduced in the query string, or can be a variable in the procedural SQL language of whatever DB engine you're using). The point is that it's the maximum value of the identity on that table.
OR, you can just dismiss the last row from the result set if you're doing it in PHP or whatever.

How to store result of a select statement into a variable?

I tried with the below code:
DECLARE #rec_count int
Set #rec_count= select 1
but it shows error
"Incorrect syntax near Select".
Either:
set #rec_count = (select 1)
or
select #rec_count = 1
An example assigning the count from a table to variable:
set #rec_count = (select COUNT(*) from master..spt_values)
select #rec_count = COUNT(*) from master..spt_values
However, if you just want to assign a value to a variable you don't need any select statement:
set #rec_count = 1
or
declare #rec_count int = 1
To store the result of a select statement into a variable, see below
DECLARE #rec_count INT
SELECT #rec_count = 1
We can get more than one value from select statement as below
DECLARE #rec_count INT
DECLARE #date DATETIME
SELECT #rec_count = 1, #date = GETDATE()
If you're trying to get a record count, which looks like what you're trying to do, you can do this:
declare #rec_count int
select #rec_count = count(1) from [your_table] -- where some condition is met
Note: Use count(1) instead of count(*) as it's quicker to simply select a single column than all when getting a count.
Or if this count is the result of some inserts/updates/selects/deletes, you can use the ##ROWCOUNT, which:
Returns the number of rows affected by the last statement.
So if for example you are performing an update or select and want to know how many rows were affected, it will automatically be stored by SQL Server in the ##ROWCOUNT.
declare #rec_count int
-- some table change
update your_table
set col1 = 1
where col1 = 0
set #rec_count = ##ROWCOUNT
-- select ##ROWCOUNT <-- this would return the number of rows updated
DECLARE #rec_count int;
Set #rec_count = 1;