I'm (attempting) to write a MySQL stored procedure that parses a large text file. Part of what this procedure does is check to see if the entities (in this case, government contractors) named in each record are already contained in the db. (This is a follow up to this question.) This is my first stored procedure and so I'm sure I've wondered off the rails here, and I would appreciated any help.
Here's what I have right now (after declaring the variables):
-- try and fetch first organization (a government agency)
SET agency = COALESCE(SELECT org_agency_o_id FROM orgs_agencies WHERE org_agency_code = maj_agency_cat,SELECT min(org_id) FROM orgs WHERE org_name LIKE CONCAT('U.S. ',SUBSTRING(maj_agency_cat,5)))
-- check to see if that worked
IF agency = NULL THEN
INSERT INTO orgs (org_name,org_name_length,org_type,org_sub_types) VALUES (CONCAT('U.S. ',SUBSTRING(maj_agency_cat,5)),LENGTH(CONCAT('U.S. ',SUBSTRING(maj_agency_cat,5))),'org','Org,GovernmentEntity,Federal,Agency');
SET agency = LAST_INSERT_ID();
END IF;
-- try and fetch second organization
SET org = COALESCE(SELECT MIN(org_id) FROM orgs WHERE org_name IN (vendorname, vendoralternatename, vendorlegalorganizationname, vendordoingasbusinessname), SELECT MIN(org_alias_org_id) FROM orgs_aliases WHERE org_alias in (endorname, vendoralternatename, vendorlegalorganizationname, vendordoingasbusinessname))
IF org = NULL THEN
INSERT INTO orgs(org_name,org_name_length,org_type,org_sub_types,org_created) VALUES (vendorname,LENGTH(vendorname),'org','org',DATE());
SET org = LAST_INSERT_ID();
END IF
Right now MySQL is throwing an error on the line:
SET agency = COALESCE(SELECT org_agency_o_id FROM orgs_agencies WHERE org_agency_code = maj_agency_cat,SELECT min(org_id) FROM orgs WHERE org_name LIKE CONCAT('U.S. ',SUBSTRING(maj_agency_cat,5)))
'maj_agency_cat' is a variable that I declare at the beginning of the procedure and then is assigned dynamically using a cursor that goes through my staging data. The full stored procedure can be viewed here.
I'm sure I'm missing something basic and would appreciate any help.
Try wrapping another () around the inner SELECT statements in your COALESCE arguments. Otherwise, they are not treated as subqueries to be executed first and the value returned, but as query objects passed into COALESCE, which is not a valid argument type for COALESCE:
SET agency = COALESCE((SELECT ..), (SELECT ..))
Related
I need to write a sequence of queries where I want to sometimes use a different table or database and don't want to keep writing them over and over again which can lead to a mistake.
SET #NAME = "Fred";
SELECT pid FROM old_table.people WHERE name = #NAME INTO #PID;
INSERT new_table.address SELECT *
FROM old_table.address o WHERE o.pid = #PID;
...
Is there a way todo a global SET or ALIAS so I don't have to repeat the database.table names again and again with the chance of a typo.
ie looking for something like this - this is not real sql
ALIAS old_table.people #OP;
ALIAS new_table.people #NP;
ALIAS old_table.address #OA;
ALIAS new_table.address #NA;
SET #NAME = "Fred";
SELECT pid FROM #OP WHERE name = #NAME INTO #PID;
INSERT #NA SELECT * FROM #OA o WHERE o.pid = #PID;
The closest thing to what you ask for is a VIEW. But I don't see how this would help avoid typos. You'd just be swapping one name for another name. You could make a typo on the view name just as easily.
You definitely cannot use a user-defined variable as a table identifier. When you use a variable in a query, it is as if you used a string value.
I am facing a strange behavior.
SELECT INTO and SET Both works for some variables and not for others. Event syntaxes are the same.
SET #Invoice_UserId := (SELECT UserId FROM invoice WHERE InvoiceId = #Invoice_Id LIMIT 1); -- Working
SET #myamount := (SELECT amount FROM invoice WHERE InvoiceId = #Invoice_Id LIMIT 1); - Not working
SELECT Amount INTO #myamount FROM invoice WHERE InvoiceId = 29 LIMIT 1; - Not working
If I run these queries directly then works, but not working in the stored procedure.
All of the syntaxes are valid and will work (apart from the invalid comment - which should be --.
If you have a problem, please post the full stored procedure.
In the stored procedure you should use local variables (DECLARE var) instead of user defined variables (#var) as local variables are strongly typed and have scope of the routine.
This is my first time creating a MySQL stored procedure and am stuck on getting the UPDATE piece to work correctly. The proc is performing an inner join, looking for matches on a domain name field. If there is a match, a column named inbound is getting updated with a value of 0. If there is not a match on the join, then I need inbound set to a value of 1.
When I run this, I am able to get the matches tagged with a 0, but the non-matches are not getting updated with a 1. I thought how I have the 'ELSE' part set up would take care of this- can anyone tell if I am missing something with the syntax?
CREATE PROCEDURE `sp_InboungTagging`()
BEGIN
update `tableA` a
inner join `TableD` d
on a.senderDomain = d.domainName
set inbound = CASE
when a.senderDomain = d.domainName then 0
ELSE 1
END
WHERE inbound is null;
END;|
DELIMITER ;
Thanks,
Ron
EDIT-
Thanks for your reply. I am looking for exact matches on a varchar field that has domain names in it- the master list of domains is in table D. If the record in TableA has a match in TableD, I want to tag that recored with a 0. If there is no match in TableD, then I would like to tag it with a 1. Let me know if that clears things up- thanks
Your JOIN condition is the same as your CASE condition. If you JOIN your two tables on:
a.senderDomain = d.domainName
Then there will be no values in the result set for which
a.senderDomain != d.domainName
so the ELSE clause of your CASE statement never fires.
Without knowing more about what you mean by "matches" and "non-matches," I can't really suggest a correction.
I have an ASP.net that requests client's information from stored procedure in SQL Server 2008 based on a client's email address until the # sign. Since the clients often change after 3 months in this small organization, but the email addresses remain the same.
E.g. a client with email address obois_in4#cegepoutaouais.qc.ca finishes his/her contract after 3-4 months and then that email address is assigned to someone else.
Now, here's my question: I want my stored procedure to find the client information, after he/she entered obois_in4 and presses the Search button. The reason I don't want them to enter the whole email is because it's too long, and secondly they can make a mistake while typing, but typing such as obois_in4 isn't a big deal.
I wrote a code that can search a client by name, but again, the clients always change after 3-4 months but the email address remains the same.
ALTER PROCEDURE [dbo].[sp_find_client_information]
-- Add the parameters for the stored procedure here
#client_email varchar (50) = null
AS Declare #numOfRows int BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT #numOfRows = COUNT (*)
From helpdesk_clients
Where --change first name and
client_firstName = #client_email or client_lastName = #client_email;
begin
if (#numOfRows = 0)
select #numOfRows;
else if (#numOfRows = 1)
select
client_id,
client_firstName,
client_lastName,
client_work_email,
client_work_phone,
client_work_phone_ext,
client_office,
dept_nom,
client_position
from
helpdesk_clients join departments
on
helpdesk_clients.dept_id = departments.dept_id
where client_firstName like '%'+#client_email+'%';
end
END
The email address always starts with obois followed by an underscore _ then the name of the department information technology as in and then by a digit such as 4 in this case. e.g. obois_in4#cegepoutaouais.qc.ca
I am surprised nobody even bothered looking into this. The best solution is to use Substring() and CharIndex()
With SUBSTRING ( expression ,start , length ) we can truncate the string starting from a position within the string until a specified position within a string. With CHARINDEX ( expressionToFind ,expressionToSearch [ , start_location ] ), we can find the the position of a character within a given string.
substring (work_email, 1, CHARINDEX('#', work_email)-1) = #work_email ensures that a parameter doesn't have to be like shawn.smith#cegepoutaouais.qc.ca, and it's a big hassle for a client to enter his full email like shawn.smith#cegepoutaouais.qc.ca, he will only be required to enter shwan.smith, the script will search for shawn.smith in shawn.smith#cegepoutaouais.qc.ca until the # sign.
e.g.
In the stored procedure, assuming the #work_email is parameter and it's value is 'shawn.smith'
select
client_id,
client_firstName,
client_lastName,
client_work_email,
client_work_phone,
client_work_phone_ext,
client_office,
dept_nom,
client_position
from
helpdesk_clients join departments
on
helpdesk_clients.dept_id = departments.dept_id
where substring (work_email, 1, CHARINDEX('#', work_email)-1) = #work_email;
Will return the all the details mentioned in the Select statement.
I' m trying to write a stored procedure that will search a fairly simple database with
a USER table (user_id,name,...)
a USER_TYPE table (user_id,type_id) - multi to multi
a TYPE table (type_id,type_name)
a USER_GAME (user_id,game_id) -multi to multi
a GAME table (game_id,game_name)
A same user can have several games. Now, I want to be able to get the user according to a particular type and also according to a/some particular game(s), so that for example I can get all the user with, say type1, and with the games, say game2 and game5. I think I can get round the problem of several game names by passing them as a string parameter and do some kind of HAVING LIKE condition (I call get_user_spec('type1' , 'game3,game5') for example).
So far I get to that point:
CREATE DEFINER=`root`#`localhost` PROCEDURE `get_user_spec`(
IN inTypeName VARCHAR(50),
IN inGameName VARCHAR(150)
)
BEGIN
PREPARE statement FROM
"SELECT u.user_id,t.type_name,GROUP_CONCAT(g.game_name) AS game
FROM user u
INNER JOIN user_type ut
ON u.user_id=ut.user_id
INNER JOIN type t
ON ut.type_id=t.type_id
LEFT JOIN user_game ug
ON u.user_id=ug.user_id
LEFT JOIN game g
ON ug.game_id=g.game_id
WHERE t.type_name=?
GROUP BY u.user_id
HAVING game LIKE CONCAT('%',?,'%')
ORDER BY u.user_id";
SET #p1=inTypeName;
SET #p2=inGameName;
EXECUTE statement USING #p1,#p2;
END
But my real problem is that if I don't pass any game name, I then want to get all users with type1 (I then call get_user_spec('type1' , NULL). But I am then not getting anything as the procedure sees
HAVING game LIKE CONCAT('%',NULL,'%').
I hope that was clear enough. If anybody has any suggestions to get around that problem, I would be very grateful.
Thank you very much.
Change this line:
EXECUTE statement USING #p1,#p2;
to
EXECUTE statement USING #p1, ifnull(#p2, '');
This will cause the LIKE expression to be just '%%', which means "match everything"