SQL SELECT statement skips rows based on WHERE statement - sql

I apologize, this may be a stupid question! I have created a procedure that maintains, and runs a series of procedures/functions. If error occurs on any procedure an email is sent to me, and an automatic refresh parameter is set with procedure name that failed. Single table houses all procedures (exact names as varchar2) to run in top-down order with looping structure. How can I skip to procedure that has failed with select statement along with grabbing all other procedures underneath procedure that has failed? Basically I would like the procedure to start where it has stopped, and continue the process of running all other procedures. I will appreciate any idea, because I am just learning.
UPDATE
For those confused. I need a SELECT statement that skips rows based on a where and grabs all other rows underneath first row. Basic psuedocode below ...
SELECT procedure_name
FROM table_whatever
SKIP ROWS that procedure_status <> 'completed'
AND grab all rows underneath
WHILST keeping rows in proper order
id procedure status
15 table_insert failed
16 table_update In Queue
17 email_completion In Queue
I need to grab failed procedure along with everything underneath.
Any ideas?
Thank you in advance!

I'll bite, what the heck. Based on your data above which assumes there can be only one row with a status of 'failed', and assumes procedures are in 'id' order:
SELECT procedure
FROM table_whatever
WHERE id >= (SELECT ID
FROM table_whatever
where status = 'failed')
ORDER by id;

Based on your minimal pseudocode, and assuming the 'proper order' is by ID, you can just exclude those that are completed:
SELECT procedure_name
FROM table_whatever
WHERE procedure_status <> 'completed'
ORDER BY id;
If you explicitly want to look for 'failed' - or so the same query can be used to kick off the sequence before anything has run - you could use an analytic query and inline view, so you only have to hit the table once:
SELECT procedure_name
FROM (
SELECT id, procedure_name, procedure_status,
MIN(CASE WHEN procedure_status = 'failed' THEN id END) OVER () AS failed_id
FROM table_whatever
)
WHERE id >= COALESCE(failed_id, 0)
ORDER BY id;
For a small table hitting it twice probably isn't too big a deal, so Gary_W's subquery approach would work just as well...

Related

T-SQL Skip cte Table and Union when Variable Is Null

I've got a query that captures all shipments and costs from our factory. Sample data and desired output on Google Drive here:
https://drive.google.com/open?id=0B4xdnV0LFZI1VndEaGgxNDVpU2M
The issue is we've got 2 different ways of selling things. One is 'Regluar' where we make it and the other one is a 'buy/sell' where we buy and sell it.
To capture the costs I've had to write two queries, one for each scenario. The end users of this query can enter in a date range and the query works well then, but I'm stuck when it comes to the variable #Job_No.
All work that goes through our factory (cteRegularJobs) has a Job Number associated with it and I've declared a variable so users can use it to search. The cteBuyandSell has a value of 'NULL' for Job_No declared in the SELECT statement so I can do a UNION of these two tables at the end. However, no buy/sell jobs have Job Numbers assigned to them, they are always NULL.
Initially #Job_No is declared as '' and when it's left '' I want the results from both cte tables returned. If there is an entry by the user, i.e. '001' then I want results for cteRegularJobs.
If it makes it easier I am open to declaring the cteBuyandSell.Job_No something else besides NULL, like "Buy and Sell".
The real query is complicated so here's a simplified example of the structure:
DELCARE #Job_No AS varchar(10) = '';
SET #Job_No = {User Input or leave as ''};
WITH
cteBuyandSell AS ( NULL AS 'Job_No',
...),
cteRegularJobs AS (tblJobs.Job_No AS 'Job_No',
...
WHERE tblJobs.Job_No LIKE #Job_No)
SELECT *
FROM
(cteBuyandSell
UNION
cteRegularJobs)
You can logically break this up with an IF statement to check the value of your variable. I'd suggest NULL over white space though. Here's an example procedure... with the limited code you provided.
CREATE PROCEDURE getData(#Job_No varchar(10) = NULL)
AS
IF #Job_No IS NULL
BEGIN
WITH
cteBuyandSell AS ( NULL AS 'Job_No',
...),
cteRegularJobs AS (tblJobs.Job_No AS 'Job_No',
...
WHERE tblJobs.Job_No LIKE #Job_No)
SELECT *
FROM
(cteBuyandSell
UNION
cteRegularJobs)
END
ELSE
BEGIN
WITH
cteRegularJobs AS (tblJobs.Job_No AS 'Job_No',
...
WHERE tblJobs.Job_No LIKE #Job_No)
SELECT * FROM cteRetularJobs
END

How should I temporarily store data within a PL/SQL procedure?

I am very new to PL/SQL. I have data in an initial table, named 'FLEX_PANEL_INSPECTIONS' that I am attempting to summarise in a second table, named 'PANEL_STATUS_2' using a PL/SQL procedure. However, due to the nature of the data, I have had to write a case statement in order to correctly summarise the data from FLEX_PANEL_INSPECTIONS. I have therefore created a third, intermediate table to bridge the two (named 'PANEL_STATUS_1') since the case statement will not allow columns in the group by clause which specifically order the data (to the extent of my knowledge - I get an error when I try and do this). I do not want to be storing data in the intermediate table - is there any way that I can either make it temporary (i.e. exist only while the procedure runs so that data from 'PANEL_STATUS_1' is not retained); create a view within the procedure, or remove the need for the intermediate table altogether?
Any help or criticism of my mistakes / misunderstanding of PL/SQL would be greatly appreciated. Here is the code I have written:
create or replace procedure PANEL_STATUS_PROCEDURE (panel_lot_id in number) as
begin
--Populate intermediate table with information about the status of the panels.
insert into PANEL_STATUS_1 (FLEX_LOT_ID, FLEX_PANEL_DMX, FLEX_PANEL_STATUS)
select FLEX_LOT_ID, FLEX_PANEL_DMX,
--Sum the status values of the 4 panel inspections. A panel passes if and only if this sum = 4.
case sum (FLEX_PANEL_STATUS)
when 4 then 1
else 0
end as new_panel_status
from FLEX_PANEL_INSPECTIONS
where FLEX_LOT_ID = panel_lot_id
group by FLEX_LOT_ID, FLEX_PANEL_DMX;
--Add information about the machine ID and the upload time to this table.
insert into PANEL_STATUS_2 (FLEX_LOT_ID, FLEX_PANEL_DMX, FLEX_PANEL_STATUS, MACHINE_ID, UPLOAD_TIME)
select distinct PANEL_STATUS_1.*, MACHINE_ID, UPLOAD_TIME
from PANEL_STATUS_1, FLEX_PANEL_INSPECTIONS
where (FLEX_PANEL_INSPECTIONS.FLEX_LOT_ID = PANEL_STATUS_1.FLEX_LOT_ID
and FLEX_PANEL_INSPECTIONS.FLEX_PANEL_DMX = PANEL_STATUS_1.FLEX_PANEL_DMX)
and FLEX_PANEL_INSPECTIONS.FLEX_LOT_ID = panel_lot_id;
end PANEL_STATUS_PROCEDURE;
/
You can create your temp table as
create global temporary table gtt_panel_status
( column datatype ... )
on commit [delete|preserve] rows;
(specifying either delete or preserve in the on commit clause).
However you usually don't need a temp table. You might try a with clause (CTE), or else an inline view along lines of select x, y, z from (select your subquery here).
Edit: actually looking at your query some more, I think what you a actually need is an analytic sum, i.e. a total without aggregating. For example, something like this:
create or replace procedure panel_status_procedure
( panel_lot_id in number )
as
begin
-- Add information about the machine ID and the upload time to this table.
insert into panel_status_2
( flex_lot_id
, flex_panel_dmx
, flex_panel_status
, machine_id
, upload_time )
select distinct
flex_lot_id
, flex_panel_dmx
, case sum(flex_panel_status) over (partition by flex_lot_id, flex_panel_dmx)
when 4 then 1
else 0
end
, machine_id
, upload_time
from flex_panel_inspections pi
where pi.flex_lot_id = panel_lot_id;
end panel_status_procedure;

SQL Server Empty Result

I have a valid SQL select which returns an empty result, up and until a specific transaction has taken place in the environment.
Is there something available in SQL itself, that will allow me to return a 0 as opposed to an empty dataset? Similar to isNULL('', 0) functionality. Obviously I tried that and it didn't work.
PS. Sadly I don't have access to the database, or the environment, I have an agent installed that is executing these queries so I'm limited to solving this problem with just SQL.
FYI: Take any select and run it where the "condition" is not fulfilled (where LockCookie='777777777' for example.) If that condition is never met, the result is empty. But at some point the query will succeed based on a set of operations/tasks that happen. But I would like to return 0, up until that event has occurred.
You can store your result in a temp table and check ##rowcount.
select ID
into #T
from YourTable
where SomeColumn = #SomeValue
if ##rowcount = 0
select 0 as ID
else
select ID
from #T
drop table #T
If you want this as one query with no temp table you can wrap your query in an outer apply against a dummy table with only one row.
select isnull(T.ID, D.ID) as ID
from (values(0)) as D(ID)
outer apply
(
select ID
from YourTable
where SomeColumn = #SomeValue
) as T
alternet way is from code, you can check count of DataSet.
DsData.Tables[0].Rows.count > 0
make sure that your query matches your conditions

No rows returned when calling stored procedure although running code in that very SP returns rows

Whenever I call a stored procedure that contains more than a single select statement I get no rows in the resultset although running the same code outside the SP returns the expected result. This has started happening by the time a database backup from a production environment was installed on the development server.
The example below returns no rows when run in Enterprise Manager 2008:
exec dbo.USP_S_CustomerLimit '00000053-0000-1148-5300-000000000000'
If I however execute all the code in that procedure by itself (like select it and press "run") I get the expected amount of result rows:
SELECT * FROM CustomerLimit WHERE Department =
(SELECT Department FROM Customer WHERE CustomerID = CONVERT(BINARY(16), CONVERT(UNIQUEIDENTIFIER, '00000053-0000-1148-5300-000000000000')))
I have also tried this variant of the code which unfortunately behaves in exactly the same way:
SELECT CustomerLimit.* FROM CustomerLimit
JOIN Customer ON Customer.Department = CustomerLimit.Department
WHERE Customer.CustomerID = CONVERT(BINARY(16), CONVERT(UNIQUEIDENTIFIER, '00000053-0000-1148-5300-000000000000'))
I feel it's some sort of right issue but I don't know where to check. I am db_owner on the server and I also belong to a group that is db_owner in the database in question. What could be the cause of this problem? If I create a testprocedure with just one select, f.e Select * from Customer then I get the correct result when executing that procedure but if I write f.e Select * from Customer where CustomerID in (select CustomerID from Customer) then I get no rows.. :(
Check whether you have rights/permission on all these three tables. Check the sys.objects for the listing of these tables.

SQL Server 2008 - Select disjunct rows

I have two concurrent processes and I have two queries, eg.:
select top 10 * into #tmp_member
from member
where status = 0
order by member_id
and then
update member
set process_status = 1
from member inner join #tmp_member m
on member.member_id=m.member_id
I'd like each process to select different rows, so if a row was already selected by the first process, then do not use that one in the second process' result list.
Do I have to play around with locks? UPDLOCK, ROWLOCK, READPAST hints maybe? Or is there a more straightforward solution?
Any help is appreciated,
cheers,
b
You need hints.
See my answer here: SQL Server Process Queue Race Condition
However, you can shorten your query above into a single statement with the OUTPUT clause. Otherwise you'll need a transaction too (asuming each process executes the 2 statements above one after the other)
update m
set process_status = 1
OUTPUT Inserted.member_id
from
(
SELECT top 10
process_status, member_id
from member WITH (ROWLOCK, READPAST, UPDLOCK)
where status = 0
order by member_id
) m
Summary: if you want multiple processes to
select 10 rows where status = 0
set process_status = 1
return a resultset in a safe, concurrent fashion
...then use this code.
Well the problem is that your select/update is not atomic - the second process might select the first 10 items in between the first process having selected and before updating.
There's the OUTPUT clause you can use on the UPDATE statement to make it atomic. See the documentation for details, but basically you can write something like:
DECLARE #MyTableVar table(member_ID INT)
UPDATE TOP (10) Members
SET
member_id = member_id,
process_status = 1
WHERE status = 0
OUTPUT inserted.member_ID
INTO #MyTableVar;
After that #MyTableVar should contain all the updated member IDs.
To meet your goal of having multiple processes work on the member table you will not need to "play around with locks". You will need to change from the #tmp_member table to a global temp table or a permanate table. The table will also need a column to track which process is managing the member row/
You will need a method to provide some kind of ID to each process which will be using the table. The first query will then be modified to exclude any entries in the table by other processes. The second query will be modified to include only those entries by this process