let me preface my question by saying, that my teacher stared at my code for 2h and could only guess that it might be the collation.
Here's the problem: for an exercise we were asked to create a movie database and then write several procedures. One procedure ist supposed to do the following:
- take the id of a movie (as a parameter), the director's last and first name
and then test wether the director already is in the table. If the answer is no, the name is added to the table. Either way, the procedure then adds the movieID and the ID of the director to a second table. Here's my code:
delimiter //
create or replace procedure p_director
( par_movieID integer, par_firstName varchar(50),par_lastName varchar(100))
BEGIN
DECLARE var_id INTEGER;
DECLARE var_firstName varchar(100);
DECLARE var_lastName varchar(100);
DECLARE var_control integer;
DECLARE exit handler for SQLEXCEPTION
Begin
rollback;
End;
Start TRANSACTION;
set var_firstName = par_firstName;
set var_lastName = par_lastName;
SELECT directorID FROM director
where lastName = var_lastName AND firstName = var_firstName
INTO var_control;
select var_control as debug;
IF (var_control IS NULL) THEN
select max(directorID)+1 from director into var_id;
insert into director ( directorid, firstName, lastName)
values (var_id, par_firstName, par_lastName);
insert into moviedirector (movieID, directorID) values
( par_movieID ,var_id) ;
ELSE
insert into moviedirector (movieID, directorID)
values ( par_movieID ,var_control);
END IF;
END//
delimiter ;
As you can see I added the line "select var_control as debug;". I did this to get the value of the variable displayed on the screen. Anyway. This code should run fine. I know this, because I wrote a routine that did the exact same thing for a homework assignment. And for that database it works.
However if I run this procedure unter MariaDB, it doe not work. Despite no syntax error, the statements between else and end if are never reached and, even stranger, the "select var_control as debug;" statement genereates no output on the screen, not even null!
As I said, my teacher stared at it for a solid 2 hours, finally he found the only difference between the code in my homework assignement and this exercise: the collation and caracterset of the database: For my homework, I used the collation latin1_swedish_ci, while at school we use utf8_general_ci.
Could this be the reason? Can the collation really have such a profound Impact? Has anyone of you ever run into thsi kind of problem?
Related
I am completely new to sql and teradata(6weeks). and have been given an assignment, which had little instruction.
(Create a stored procedure that allows a user to select a bat’s manufacturer and (optionally) serial number using a stored procedure. The output should display all of the players who use the bat’s manufacturer. If the serial number is also provided, only display the players who use that bat’s manufacturer and serial number. Make sure you use a CREATE PROCEDURE call and insert this procedure into the existing database. ) this is a database through teradata that has been duplicated into my own database to be edited. This is what I got so far and it keeps returning two errors. I'd love help with a solution and best possible recommendation for learning sql quickly and efficiently. I appreciate the help in advance. and i'm sure this is the ugliest code you've seen, I aplogize. :-D
CREATE PROCEDURE batman(manuf varchar(20), bat_type varchar(4)=null)
DYNAMIC RESULT SETS 2
BEGIN
DECLARE c CURSOR FOR
SELECT playernum
FROM affiliation, bats
WHERE manuf = :manuf;
declare serial cursor for
select playernum
from affiliation
where bat_type=NULL or bat_type=:bat_type
if bat_type=NULL then open c
else open serial;
end if;
END;
The default of a parameter is always NULL, no need to declare that.
You can't compare NULLs using =, must be is null instead.
And there are some missing semicolons...
CREATE PROCEDURE batman(manuf VARCHAR(20), bat_type VARCHAR(4))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE c CURSOR FOR
SELECT playernum
FROM affiliation, bats
WHERE manuf = :manuf;
DECLARE serial CURSOR FOR
SELECT playernum
FROM affiliation
WHERE bat_type IS NULL OR bat_type=:bat_type;
IF bat_type IS NULL THEN OPEN c;
ELSE OPEN serial;
end if;
END;
I am trying to search through a column in one table (Asset_Database_Current) with the details from a column in another table (DNI_Names). I've written a loop to go through each DNI_Name, and then a SELECT CONTAINS statement to (hopefully) compare DNI_Name against the relevant column in Asset_Database_Current.
I've set up a FullText Catalog and have indexed the Asset_Database_Current table to be searchable.
This is the code I have:
DECLARE
#Asset varchar(8)
, #software_Name VARCHAR(64)
, #dniSW VARCHAR(64)
, #DNI VARCHAR(64)
CREATE TABLE #temp_naughtyChildren (naughtyAsset CHAR(8), naughtySW VARCHAR(64))
-- ^ where the Naughty People eventually get put
DECLARE #dni_cur CURSOR FOR
SELECT DNI_Names.DNI_Name
FROM DNI_Names
OPEN #dni_cur
FETCH NEXT FROM #dni_cur
INTO #DNI
WHILE ##FETCH_STATUS = 0
BEGIN -- we go through DNI_Names, selecting each instance of DNI_Name one at a time...
INSERT INTO #temp_naughtyChildren (naughtyAsset, naughtySW)
SELECT Asset_Number, Software_Name
FROM Asset_Database_Current
WHERE CONTAINS (Asset_Database_Current.Software_Name, #DNI)
FETCH NEXT FROM #dni_cur
INTO #DNI
END
DEALLOCATE #dni_cur
-- #temp_NaughtyChildren is now full of all the Asset Numbers and swName's of people who
-- have been very, very naughty. The table can now be used as required (emailed, sent to
-- another d/b, etc.).
SELECT * from #temp_NaughtyChildren ORDER BY naughtyAsset
DROP TABLE #temp_naughtyChildren
END
GO
The above code completes successfully, but when I try and execute the query I get the following error twice:
Msg 7630, Level 15, State 3, Procedure DNIChecker, Line 44
Syntax error near 'Manager' in the full-text search condition 'App Manager'.
My boss has also executed the query (he has full permissions on the database) and he gets the exact same error.
Any suggestions you can give me will be very gratefully received (I haven't done SQL since 1998, I've realised that when they teach you SQL at Uni they don't actually teach you much SQL, and I have spent the last 2 1/2 weeks trawling various sites working on this. Only yesterday did I finally stumble across an article that mentioned there was a wizard to set up full-text search!!).
Thanks, M
CONTAINS require qoutes around the search condition if you use a full phrase, otherwise you should use NEAR, AND, OR between the single words.
SET #DNI = '"' + #DNI + '"';
INSERT INTO #temp_naughtyChildren (naughtyAsset, naughtySW)
SELECT Asset_Number, Software_Name
FROM Asset_Database_Current
WHERE CONTAINS (Asset_Database_Current.Software_Name, #DNI)
I am creating a stored procedure to create a new customer so for instance,
CREATE PROCEDURE Customer_Create
#customer_arg
#type_arg
AS
BEGIN
INSERT INTO Customer (Customer_id, Type_id)
VALUES (#Customer_arg,#type_arg)
End;
If I have several foreign keys in my statement and they are all ID's is there a way for me to pull the NEXT ID number automatically without having to know what it would be off the top of my head when I run the execute statement? I would like to just have it pull the fact that the ID will be 2 because the previous record was 1
EXECUTE Customer_Create 16,2
Is it something wnith output? If so how does this work code wise
I suspect that what you want to do is return the new id after the record is inserted. For that:
CREATE PROCEDURE Customer_Create (
#customer_arg,
#type_arg,
#NewCustomerId int output
) AS
BEGIN
INSERT INTO Customer(Customer_id, Type_id)
VALUES (#Customer_arg, #type_arg);
#NewCustomerId = scope_identity();
End;
There are several other choices for getting the identity, which are explained here.
To get to the last inserted IDENTITY value you should use the OUTPUT clause like this:
DECLARE #IdentValues TABLE(v INT);
INSERT INTO dbo.IdentityTest
OUTPUT INSERTED.id INTO #IdentValues(v)
DEFAULT VALUES;
SELECT v AS IdentityValues FROM #IdentValues;
There are several other mechanisms like ##IDENTITY but they all have significant problems. See my Identity Crisis article for details.
In your case you can also experiment with #IDENTITY like this
DECLARE #NextID int
--insert statement goes here
SET #NextID = ##Identity`
Here are couple good resources for getting familiar with this
http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/
http://blog.sqlauthority.com/2013/03/26/sql-server-identity-fields-review-sql-queries-2012-joes-2-pros-volume-2-the-sql-query-techniques-tutorial-for-sql-server-2012/
IBM Informix Dynamic Server Version 11.50.FC6
I was working on a small stored procedure that would take name fields from a table and parse them into "user names" with a maximum of 8 chars.
This is the code I was trying:
CREATE PROCEDURE build_jics_user (pid INT)
RETURNING CHAR(8) AS username;
SELECT LOWER((SUBSTR(firstname,0,1))||(SUBSTR(lastname,0,7))) username
FROM id_rec
WHERE id = pid;
END PROCEDURE;
The error returned when executed is:
659: INTO TEMP table required for SELECT statement.
Error in line 5
Near character position 15
I don't understand what the point of summoning a temporary table is, and I also couldn't find any similarly simple examples online that would work without error.
Does anyone know what I'm missing?
What you want to say is this:
CREATE PROCEDURE build_jics_user (pid INT)
RETURNING CHAR(8);
DEFINE username CHAR(8);
SELECT LOWER((SUBSTR(firstname,0,1))||(SUBSTR(lastname,0,7))) INTO username
FROM id_rec
WHERE id = pid;
RETURN username;
END PROCEDURE;
... and execute it like this:
EXECUTE PROCEDURE build_jics_user(42);
UPDATE
If the purpose of this is to be a function, where it's required inside some other SQL, then you might do the following:
CREATE FUNCTION jics_user(fname VARCHAR(255), lname VARCHAR(255))
RETURNING CHAR(8);
RETURN LOWER(SUBSTR(fname,0,1) || SUBSTR(lname,0,7));
END FUNCTION;
... and execute it like this:
SELECT id, firstname, lastname, jics_user(firstname, lastname) AS jics_user, ...
FROM id_rec;
There's no real technical difference between a PROCEDURE and a FUNCTION, it's more an assertion as to how it's used.
This seems to be per design (which must be accounting for the absence of the 'similarly simple examples online'). Apparently, whatever data you are pulling with a SELECT statement in a stored procedure, you cannot return them directly. You should store them either in a temporary table or in variables for later use.
It is likely that your SELECT statement should look like this
SELECT LOWER((SUBSTR(firstname,0,1))||(SUBSTR(lastname,0,7))) INTO username
FROM id_rec
WHERE id = pid;
I'm having a weird error that happens under weird circumstances.
The list of skill names I receive in the cursor curLongSkills is to be inserted into the table tbl_new_skill_overview if and only if they don't already exist. So I loop through the cursor as usual, and check whether it already exists before inserting.
The weird thing is that I receive the error Syntax error converting the varchar value 'Some Random Skill' to a column of data type int. on the line SELECT #iCount = COUNT(ID).
However, this does not happen if I remove the WHERE clause in that statement. So if I comment or remove WHERE Name = #sSkillName, it won't give the error. It's as if it thinks that I'm assigning #sSkillName to #iCount just because I'm using #sSkillName in the WHERE clause of the same query.
Other ways of doing this will suffice provided that I can tell whether or not the skill has already been inserted into tbl_new_skill_overview. I don't necessarily have to do it this way.
I've also tried the following, which gives the same error:
SET #iCount = (
SELECT COUNT(ID) AS Line_Count
FROM tbl_new_skill_overview
WHERE Name = #sSkillName
);
The server is running Microsoft SQL Server 2000 (I know, I know...).
Following is the entire SQL script.
DECLARE #sSkillName VARCHAR(200);
DECLARE #iCount INT;
DECLARE curLongSkills CURSOR FOR (
SELECT DISTINCT Name
FROM tbl_new_skill
WHERE Profile = 'long'
AND Parent_ID IS NULL
)
OPEN curLongSkills;
FETCH curLongSkills INTO #sSkillName;
WHILE ##FETCH_STATUS = 0 BEGIN
SELECT #iCount = COUNT(ID)
FROM tbl_new_skill_overview
WHERE Name = #sSkillName; -- No error if this line removed.
IF #iCount = 0 BEGIN
PRINT #sSkillName;
-- TODO: Insert skill
END;
FETCH curLongSkills INTO #sSkillName;
END;
CLOSE curLongSkills;
DEALLOCATE curLongSkills;
I've never liked cursors - but as a cheeky alternative, you should be able to accomplish what you want without a cursor.
insert into tbl_new_skill_overview
select //columnNames
from tbl_new_skill
WHERE Profile = 'long'
AND Parent_ID IS NULL
and name not in
(select name from tbl_new_skill)
The problem was stupidity.
The Name column in tbl_new_skill_overview was mistakenly put in as an INT, not a VARCHAR.
Thanks to all who responded, particularly bobs for asking me to show the database structure, at which point I realized the mistake.
That's a strange occurrence for sure. I have no idea what's causing it, but to get around it, perhaps you could do something like this:
if not exists (select * from tbl_new_skill_overview where Name = #sSkillName) begin
print #sSkillName;
-- TODO: Insert skill
end
That is assuming you don't use #iCount for anything else later.