UPDATE - I have figured out how to add the stored procedures using code-first migration. 'All' I am wondering now is how I can apply a SELECT * FROM _tempTable1_ UNION SELECT * FROM _tempTable2, and then output this. I was thinking of implementing a third stored procedure which does this but I am not sure whether this is the right thing to do? Much appreciated help:)
I have a table connected to my ASP.NET MVC application, and I have created two stored procedures in SQL Server. Is it possible to implement these stored procedures in a way so that when the table is output, it can be grouped into these stored procedures?
MetBasicCriteria
ALTER PROCEDURE [dbo].[MetBasicCriteria]
-- Add the parameters for the stored procedure here
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT *
FROM dbo.Applications
WHERE NorwegianCitizen=1
AND CurrentlyInUni=1
AND Norwegian=1
AND English=1
END
MetMoreCriteria
ALTER PROCEDURE [dbo].[MetMoreCriteria]
-- Add the parameters for the stored procedure here
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
--EXEC [dbo.MetBasicCriteria]
SELECT *
FROM dbo.Applications
WHERE (Dutch=1
OR OtherCitizenships='Dutch'
OR (Course_bachelor='Political Science' OR Course_bachelor='Economy' OR Course_bachelor='International Relations')
OR (Grade_Bachelor='a' OR Grade_Bachelor='A' OR Grade_Bachelor='b' OR Grade_Bachelor='B'))
--AND MetBasicCriteria=1
END
In other words --> can I use say 3 different stored procedures, save the outcomes of these 3 into different temporary tables, and the using UNION ALL combine them into 1 temporary table?
Thanks in advance
I just take your second procedure code and modify it as a simple POC. I have no idea how you intend to merge or alter or combine the resultsets from your first procedure with that of your second procedure. So I leave that for you. I will also remove the meaningless comments you leave in the code since you seem to be using some sort of template.
ALTER PROCEDURE [dbo].[MetMoreCriteria]
AS
BEGIN
SET NOCOUNT ON;
create table #basic (
id int not null,
...
);
Insert #basic (id) --column list to be defined
EXEC [dbo.MetBasicCriteria];
SELECT appl.id, ...
FROM dbo.Applications as appl
WHERE (appl.Dutch=1
OR appl.OtherCitizenships='Dutch'
OR (appl.Course_bachelor in ('Political Science', 'Economy', 'International Relations'))
OR (appl.Grade_Bachelor in ('A', 'a', 'B', 'b'))
)
AND EXISTS (SELECT * FROM #basic as basic where basic.id = appl.id)
ORDER BY ...;
END
Hopefully I used the parentheses correctly but I can't test it and this edit widget does not auto-count or correct typos or mistakes. Some better coding points:
define an alias for each table and use it for every column reference.
don't use "*" generally as a column list
Using IN rather than a series of logical OR comparisons makes your code more readable and less prone to error
The column list in the SELECT and INSERT statements should be specific - don't use the lazy asterisk to select all columns since you typically don't need them all. If you do need them all, then specify each column to avoid future problems if the schema of the tables changes. The only place where "*" is acceptable as a column list is inside an EXISTS clause.
I also added the ORDER BY clause since the consumer of a resultset usually wants those rows ordered. But perhaps your application/consumer does not care? If so, remove it and save some processor cycles.
Lastly this is just one approach. You could also make your first procedure a view or a UDF since it does nothing complicated. And that comment can also apply to this procedure. Perhaps you are just over-complicating a rather simple set of logic? NB that I omit any error-handling and leave that to you. And let me re-iterate that this is NOT a recommendation. Simply one implementation option.
Related
For my homework I need to make a package that contains a procedure that removes all records from the table dwdimartist and then fills the table with all records from the table artist and add a field with the date of today.
This is what I've created, it works but I don't know if it's performant enough. Is it better to use a cursor that loops over each record in the table artist?
CREATE OR REPLACE PACKAGE BODY dwh AS
PROCEDURE filldwh IS
today_date DATE := SYSDATE;
BEGIN
DELETE FROM dwdimartist;
INSERT INTO dwdimartist (artistkey, name) (SELECT artistid, name FROM artist);
UPDATE dwdimartist SET added = today_date;
END filldwh;
END dwh;
Simple SQL query like you did is better choice than a cursor or implicit loop.
possible improvement:
You should do it at once without update: set the date during insert.
INSERT INTO dwdimartist (artistkey, name, added)
(SELECT artistid, name, sysdate FROM artist);
Hope it helps
You don’t need to use cursors. You can hardly beat Insert ... select since it’s SQL itself and in most cases it works better than any programmatic structure due to native dbms optimization. However, you can do better if you decrease number of I/O operations. You don’t need update here. Simply add sysdate to your select and insert everything together.
insert into dwdimartist(artistkey, name, added) select artistid, name, sysdate from artist;
Another thing to improve is your ‘delete’. While it’s small table for learning purposes you won’t feel any difference between delete and truncate but for real ETL tasks and big tables you’ll see it definitely. Yes you cannot use truncate directly in your PL/SQL but there are 3 ways to do it:
execute immediate ‘truncate dwdimartist’;
Dbms_utility.exec_ddl_statement(‘truncate ...;’);
DBMS_SQL package
However, remember that calling truncate will execute commit like any ddl command. So delete may be the only option sometimes. But even if it is, you should avoid it for the whole table.
I have been asked to create an SP which creates temporary table and insert some records.
I am preparing some sample code for the same as mentioned below but the output is not displayed.
create or replace procedure Test
is
stmt varchar2(1000);
stmt2 varchar2(1000);
begin
stmt := 'create global temporary table temp_1(id number(10))';
execute immediate stmt;
insert into temp_1(id) values (10);
execute immediate 'Select * from temp_1';
execute immediate 'Drop table temp_1';
commit;
end;
When i am executing the SP by (Exec Test) desired O/P is not displayed.
I am expecting O/P of "Select * from temp_1" to be displayed. But it is not happening. Please suggest where i am doing wrong.
But i am interesting in knowing why ( execute immediate 'Select * from temp_1';) do not yield any result
For two reasons. Firstly because as #a_horse_with_no_name said PL/SQL won't display the result of a query. But more importantly here, perhaps, the query is never actually executed. This behaviour is stated in the documentation:
If dynamic_sql_statement is a SELECT statement, and you omit both into_clause and bulk_collect_into_clause, then *execute_immediate_statement( never executes.
You would have to execute immediate into a variable, or more likely a collection if your real scenario has more than one row, and then process that data - iterating over the collection in the bulk case.
There is not really a reliable way to display anything from PL/SQL; you can use dbms_output but that's more suited for debugging than real output, and you usually have no guarantee that the client will be configured to show whatever you put into its buffer.
This is all rather academic since creating and dropping a GTT on the fly is not a good idea and there are better ways to accomplish whatever it is you're trying to do.
The block you showed shouldn't actually run at all; as you're creating temp_1 dynamically, the static SQL insert into temp_1 will error as that table does not yet exist when the block is compiled. The insert would have to be dynamic too. Any dynamic SQL is a bit of a warning sign you're maybe doing something wrong, though it is sometimes necessary; having to do everything dynamically suggests the whole approach needs a rethink, as does creating objects at runtime.
I have been having this question for while now
we can Implement a cursor for Example
SET serveroutput ON;
DECLARE
CURSOR test_cursor
IS
SELECT * FROM employees;
BEGIN
FOR i IN test_cursor
LOOP
DBMS_OUTPUT.PUT_LINE(i.employee_id||' '||i.First_name);
END LOOP;
END;
Also we can implement the same in below way
SET serveroutput ON;
BEGIN
FOR rec IN
(SELECT * FROM employees
)
LOOP
DBMS_OUTPUT.PUT_LINE(rec.employee_id ||' ' ||rec.First_name);
END LOOP;
END;
Why do we need a cursor here then? Please could you let me know the differences and its advantages/disadvantages?
In both cases, you actually use cursors.
The first one is declared and named (explicit).
The second one is anonymous (implicit).
http://docs.oracle.com/cd/B10501_01/appdev.920/a96624/01_oview.htm#740.
I usually use explicit cursors for better code readability and in cases, when I want to reuse the cursor, I can fetch the data from result cache or fetch the data into variable and iterate through an array.
Also, as far as I know, execution plan is not generated as often as while using the implicit cursor (the DB searches for the query in SGA by query's hash and can find already stored execution plan, thus skips the execution plan generation).
https://docs.oracle.com/database/121/TGSQL/tgsql_sqlproc.htm#TGSQL175
So firstly, these are both known as cursor FOR LOOPs.
http://docs.oracle.com/database/121/LNPLS/cursor_for_loop_statement.htm#LNPLS1143
One usability difference between the two forms is that the second form places the SQL that is executing directly before the code in which the result set is used. This can make it easier to understand the code.
One useful syntax difference is that in the first form you can pass parameters into the cursor to modify its behaviour (see above link for syntax). So if you use the same basic cursor definition multiple times, but with different parameters to pass in, then use the former.
I would like to ask you how would you increase the performance on Insert cursor in this code?
I need to use dynamic plsql to fetch data but dont know how to improve the INSERT in best way. like Bulk Insert maybe?
Please let me know with code example if possible.
// This is how i use cur_handle:
cur_HANDLE integer;
cur_HANDLE := dbms_sql.open_cursor;
DBMS_SQL.PARSE(cur_HANDLE, W_STMT, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS2(cur_HANDLE, W_NO_OF_COLS, W_DESC_TAB);
LOOP
-- Fetch a row
IF DBMS_SQL.FETCH_ROWS(cur_HANDLE) > 0 THEN
DBMS_SQL.column_value(cur_HANDLE, 9, cont_ID);
DBMS_SQL.COLUMN_VALUE(cur_HANDLE, 3, proj_NR);
ELSE
EXIT;
END IF;
Insert into w_Contracts values(counter, cont_ID, proj_NR);
counter := counter + 1;
END LOOP;
You should do database actions in sets whenever possible, rather than row-by-row inserts. You don't tell us what CUR_HANDLE is, so I can't really rewrite this, but you should probably do something like:
INSERT INTO w_contracts
SELECT ROWNUM, cont_id, proj_nr
FROM ( ... some table or joined tables or whatever... )
Though if your first value there is a primary key, it would probably be better to assign it from a sequence.
Solution 1) You can populate inside the loop a PL/SQL array and then just after the loop insert the whole array in one step using:
FORALL i in contracts_tab.first .. contracts_tab.last
INSERT INTO w_contracts VALUES contracts_tab(i);
Solution 2) if the v_stmt contains a valid SQL statement you can directly insert data into the table using
EXECUTE IMMEDIATE 'INSERT INTO w_contracts (counter, cont_id, proj_nr)
SELECT rownum, 9, 3 FROM ('||v_stmt||')';
"select statement is assembled from a website, ex if user choose to
include more detailed search then the select statement is changed and
the result looks different in the end. The whole application is a web
site build on dinamic plsql code."
This is a dangerous proposition, because it opens your database to SQL injection. This is the scenario in which Bad People subvert your parameters to expand the data they can retrieve or to escalate privileges. At the very least you need to be using DBMS_ASSERT to validate user input. Find out more.
Of course, if you are allowing users to pass whole SQL strings (you haven't provided any information regarding the construction of W_STMT) then all bets are off. DBMS_ASSERT won't help you there.
Anyway, as you have failed to give the additional information we actually need, please let me spell it out for you:
will the SELECT statement always have the same column names from the same table name, or can the user change those two?
will you always be interested in the third and ninth columns?
how is the W_STMT string assembled? How much control do you have over its projection?
Here's the situation. Due to the design of the database I have to work with, I need to write a stored procedure in such a way that I can pass in the name of the table to be queried against if at all possible. The program in question does its processing by jobs, and each job gets its own table created in the database, IE table-jobid1, table-jobid2, table-jobid3, etc. Unfortunately, there's nothing I can do about this design - I'm stuck with it.
However, now, I need to do data mining against these individualized tables. I'd like to avoid doing the SQL in the code files at all costs if possible. Ideally, I'd like to have a stored procedure similar to:
SELECT *
FROM #TableName AS tbl
WHERE #Filter
Is this even possible in SQL Server 2005? Any help or suggestions would be greatly appreciated. Alternate ways to keep the SQL out of the code behind would be welcome too, if this isn't possible.
Thanks for your time.
best solution I can think of is to build your sql in the stored proc such as:
#query = 'SELECT * FROM ' + #TableName + ' as tbl WHERE ' + #Filter
exec(#query)
not an ideal solution probably, but it works.
The best answer I can think of is to build a view that unions all the tables together, with an id column in the view telling you where the data in the view came from. Then you can simply pass that id into a stored proc which will go against the view. This is assuming that the tables you are looking at all have identical schema.
example:
create view test1 as
select * , 'tbl1' as src
from job-1
union all
select * , 'tbl2' as src
from job-2
union all
select * , 'tbl3' as src
from job-3
Now you can select * from test1 where src = 'tbl3' and you will only get records from the table job-3
This would be a meaningless stored proc. Select from some table using some parameters? You are basically defining the entire query again in whatever you are using to call this proc, so you may as well generate the sql yourself.
the only reason I would do a dynamic sql writing proc is if you want to do something that you can change without redeploying your codebase.
But, in this case, you are just SELECT *'ing. You can't define the columns, where clause, or order by differently since you are trying to use it for multiple tables, so there is no meaningful change you could make to it.
In short: it's not even worth doing. Just slop down your table specific sprocs or write your sql in strings (but make sure it's parameterized) in your code.