Stored procedure that takes list of string as input and insert missing rows then return them - sql

I have a table Names
Id Name
+----+---------------+
1 John
2 Kate
3 Mark
I want to create a stored procedure that does the following:
1) take a list of names as string as an input parameter
I have done some researches about this but couldn't find the best way to do it. I will call the stored procedure from the entity framework in a C# application. I was thinking of passing the names in one string separated with a comma and the split them in the procedure. But can't figure out how this is done.
2) for each name in the list, if the name does not exist in the Name column, insert a new row for it.
How can I do a switch case if it exists and insert it if not
3) Select * rows that are in the input list.
After adding all the missing Names, I want to select all the names that were in the input list with their id
Can this be done in one stored procedure, or do I have to divide them into multiple.
I am looking for hints on how to do each step, and if they can be combined.
Thanks

Keep your DB side lean and leave logic on the app side, especially if you have grumpy DBA's.
Use a MERGE/Upsert instead.
Check out this SO post.

If you pass a comma delimited list into a stored procedure as a parameter, you are going to need to understand how to use charindex, left, substring and right
As you split out each name - you would add them into a temporary table or a table valued variable.
Your decision about whether to insert the new names into the Names table would be made using an exists() subquery on an insert statement.
You could then, finally, fashion a select statement to join your temp table/table valued variable back to your Names table to pull out all of the keys (including the new ones) and pass them back to your front end.

Related

PL SQL select count(*) giving wrong answer

I have I table consisting of 3 columns: system, module and block. Table is filled in a procedure which accepts system, module and block and then it checks if the trio is in the table:
select count(*) into any_rows_found from logs_table llt
where system=llt.system and module=llt.module and block=llt.block;
If the table already has a row containing those three values, then don't write them into the table and if it doesn't have them, write them in. The problem is, if the table has values 'system=a module=b block=c' and I query for values 'does the table have system=a module=d block=e' it returns yes, or, to be precise, any_rows_found=1. Value 1 is only not presented when I send a trio that doesn't have one of it's values in the table, for example: 'system=g module=h and block=i'. What is the problem in my query?
Problem is in this:
where system = llt.system
Both systems are the same, it is as if you put where 1 = 1, so Oracle is kind of confused (thanks to you).
What to do? Rename procedure's parameters to e.g. par_system so that query becomes
where llt.system = par_system
Another option (worse, in my opinion) is to precede parameter's name with the procedure name. If procedure's name was e.g. p_test, then you'd have
where llt.system = p_test.system
From the documentation:
If a SQL statement references a name that belongs to both a column and either a local variable or formal parameter, then the column name takes precedence.
So when you do
where system=llt.system
that is interpreted as
where llt.system=llt.system
which is always true (unless it's null). It is common to prefix parameters and local variables (e.g. with p_ or l_) to avoid confusion.
So as #Littlefoot said, either change the procedure definition to make the parameter names different to the column names, or qualify the parameter names with the procedure name - which some people prefer but I find more cumbersome, and it's easier to forget and accidentally use the wrong reference.
Root cause is alias used for table name.
where system=llt.system and module=llt.module and block=llt.block;
Table name alias in select query and input to procedure having the same name(i.e. llt
). You should consider either renaming one of them.

Store SQL query result (1 column) as Array

After running my query I get 1 column result as
5
6
98
101
Is there a way to store this result as array so that I can use it later
in queries like
WHERE NOT IN ('5','6','98','101')
I am aware of storing single variable results but is this possible?
I can not use #Table variable as I will be rerunning the query again in the future and it goes out of scope
There are multiple way of storing those column data like using Temporary Tables or View or Table valued function but IMO there is no need of storing that column data anywhere. You can directly use that column in any query saying below (or) perform a JOIN which would be much better option than NOT IN
select * from
table2
where some_column not in (select column1 from this_table);
While this method is not recommended, storing an array in a single column can be done using CSV's(Comma Separated Values). Simply create a VARCHAR array and store it by storing a string containing the values in a specific order. Basically store all of your values into a string with each value being separated by a comma in that string. Store that into a column of your choice. You can later fetch the string and parse it with a string parser i.e using the .split() function in python. AGAIN I do not recommend doing this, I would instead use multiple columns, one referring to each value and access them that way instead
Using separate columns would make it easy to use in a Stored Procedure.

How to pass two list of values to stored procedure in SQL Server?

So i am trying for writing a procedure which need to accept the input values in form of two lists as follows:
execute ProcedureForInsert 'john,marry,tom' '1,2,3' 40
where first parameter is list of Varchar type and second is list of int type and length of both lists are to be same and third parameter is also of int type.
My script is to use these two list values to insert into some table along with third parameter.
How to store and iterate two lists for creation of Insert Query .
Thanks in advance.
You need a "split string" function that takes a comma separated list and produces a table of the individual strings as output. There are a lot of these to be found, but look here to start:
How to split a comma-separated value to columns

How to replace a string with values from columns in a table in SQL

I have a table like the following
Exp Major Start
---------------------------------- ----------- -------
My names ar W.Major and W.Start Hal Bark
W.Major is a doctor Mark Slope
I want to write a SQL query to replace W.Major or W.start in the exp column with the values in the columns Major and Start.
Can someone please suggest me a way to do this?
The key is using two replace functions.
Update tablename
set exp = replace (replace (exp, 'W.Major', major), 'W.Start', start);
Read more about replace on MSDN. This function is more or less the same across all major RDBMSes.
EDIT:
In a scenario where you don't know how many keywords and replacement columns are there in your text, I'd suggest you create a stored procedure in which you do the following:
Use a temporary table that has two columns- one for the search key, e.g. 'W.Major', and the other with the name of the column , e.g. 'major'. Note that you don't have to store the values from that column, just the name of the column. Like this:-
key replacement_col
---------- -----------------
W.Major major
W.Start start
... and so on.
Now build a dynamic SQL looping in with your main table and this temporary table. Loop the way you find comfortable. I would suggest the following method of looping:
a) From the first row to the last row in your main table, select the column exp.
b) Loop through this value of exp to search for any search keywords. Look for the keywords and values in your temp table.
c) Prepare a dynamic SQL statement which would then write an update query with nested replace calls for you. Execute this dynamic SQL.

MySQL - Set default value for field as a string concatenation function

I have a table that looks a bit like this actors(forename, surname, stage_name);
I want to update stage_name to have a default value of
forename." ".surname
So that
insert into actors(forename, surname) values ('Stack', 'Overflow');
would produce the record
'Stack' 'Overflow' 'Stack Overflow'
Is this possible?
Thanks :)
MySQL does not support computed columns or expressions in the DEFAULT option of a column definition.
You can do this in a trigger (MySQL 5.0 or greater required):
CREATE TRIGGER format_stage_name
BEFORE INSERT ON actors
FOR EACH ROW
BEGIN
SET NEW.stage_name = CONCAT(NEW.forename, ' ', NEW.surname);
END
You may also want to create a similar trigger BEFORE UPDATE.
Watch out for NULL in forename and surname, because concat of a NULL with any other string produces a NULL. Use COALESCE() on each column or on the concatenated string as appropriate.
edit: The following example sets stage_name only if it's NULL. Otherwise you can specify the stage_name in your INSERT statement, and it'll be preserved.
CREATE TRIGGER format_stage_name
BEFORE INSERT ON actors
FOR EACH ROW
BEGIN
IF (NEW.stage_name IS NULL) THEN
SET NEW.stage_name = CONCAT(NEW.forename, ' ', NEW.surname);
END IF;
END
According to 10.1.4. Data Type Default Values no, you can't do that. You can only use a constant or CURRENT_TIMESTAMP.
OTOH if you're pretty up-to-date, you could probably use a trigger to accomplish the same thing.
My first thought is if you have the two values in other fields what is the compelling need for redundantly storing them in a third field? It flies in the face of normalization and efficiency.
If you simply want to store the concatenated value then you can simply create a view (or IMSNHO even better a stored procedure) that concatenates the values into a pseudo actor field and perform your reads from the view/sproc instead of the table directly.
If you absolutely must store the concatenated value you could handle this in two ways:
1) Use a stored procedure to do your inserts instead of straight SQL. This way you can receive the values and construct a value for the field you wish to populate then build the insert statement including a concatenated value for the actors field.
2) So I don't draw too many flames, treat this suggestion with kid gloves. Use only as a last resort. You could hack this behavior by adding a trigger to build the value if it is left null. Generally, triggers are not good. They add unseen cost and interactions to fairly simple interactions. You can, though, use the CREATE TRIGGER to update the actors field after a record is inserted or updated. Here is the reference page.
As of MySQL 8.0.13, you can use DEFAULT clause for a column which can be a literal constant or an expression.
If you want to use an expression then, simply enclose the required expression within parentheses.
(concat(forename," ",surname))
There are two ways to accomplish what you are trying to do as per my knowledge:
(important: consider backing up your table first before running below queries)
1- Drop the column "stage_name" all together and create a new one with DEFAULT constraint.
ALTER TABLE actors ADD COLUMN stage_name VARCHAR(20) DEFAULT (concat(forename," ",surname))
2- This will update newer entries in the column "stage_name" but not the old ones.
ALTER TABLE actors alter stage_name set DEFAULT (concat(forename," ",surname));
After that, if you need to update the previous values in the column "stage_name" then simply run:
UPDATE actors SET stage_name=(concat(forename," ",surname));
I believe this should solve your problem.