Get System Error Message In Sybase - sybase-ase

I am writing a procedure and doing error handling after each step. If an error comes, I return an error code with custom user friendly error message.
But due to some requirement, I also have to pass system error message.
Sample :
Ex: I am inserting some records into table and if something goes wrong , I have error message to handle it.
Insert into A
Select top 250 id from C
inner join D
on c.id = D. id
IF (##error != 0)
BEGIN
SELECT #p_err_code = 1
SELECT #p_err_desc = "Error while inserting records into #PAR_PROVIDERS."
<---------- how to pass system error message here-------->
DROP TABLE #PAR_PROVIDERS
RETURN 1
END

I don't know how to take specify error message - I think it's not possible. Maybe below query will cover your needs. It return and pattern message for example Must declare variable '%.*s'. insetad of Must declare variable 'fake variable'.
SELECT description
from master..sysmessages where error = ##error
##error variable change every time you make an operation so you need to use local variable for example #err. In your code should be like this.
declare #err int,
#msg varchar(255)
Insert into A
Select top 250 id from C
inner join D
on c.id = D. id
select #err = ##error
IF (#err != 0)
BEGIN
SELECT #p_err_code = 1
SELECT #p_err_desc = "Error while inserting records into #PAR_PROVIDERS."
SELECT #msg = description
from master..sysmessages where error = #err
DROP TABLE #PAR_PROVIDERS
RETURN 1
END

Related

Update row with data from another row in different tables

I am new to MySQL and not too sure how can I update row from another table while checking if logged in user is the same:
Telefonist='".$_SESSION["UserName"]."
And also I need to check if date is the same so it gets to right person on right date in a row:
log.Datum=telefonisti_podaci.Datum
here I am trying to count all 1s and enter sum from table1 to table2 in specific place.
Code:
$sql_zapis_do30 = "UPDATE telefonisti_podaci
SET `Total tura do 30` = (Select COUNT(*) `Ture do 30` from log,telefonisti_podaci WHERE `Ture do 30` is not null AND `Ture do 30`=1 AND log.Datum=telefonisti_podaci.Datum )
WHERE `Telefonist`='".$_SESSION["UserName"]."'";
CustomQuery($sql_zapis_do30);
I get error:
You can't specify target table 'telefonisti_podaci' for update in FROM clause
Thanks
I have solved it like this:
$sql_zapis_do30 = "UPDATE telefonisti_podaci
SET `Total tura do 30` = (Select COUNT(`Ture do 30`) from log WHERE `Telefonist`='".$_SESSION["UserName"]."' AND `Ture do 30`=1 AND `Datum`='".$datum_danas."')
WHERE `Telefonist`='".$_SESSION["UserName"]."' AND `Datum`='".$datum_danas."'";
And it works for now
Thanks

Delete all rows from a table when total row count exceeds a number

I am trying to optimize my queries and I have the following code:
<?php
$counter = mysql_query("SELECT COUNT(*) AS c FROM table");
$row = mysql_fetch_array($counter);
$count = $row["c"];
if($count>500){
mysql_query("DELETE FROM table");
}
?>
I tried the below syntax as a test and it worked:
Select case when (Select count(*) as t from `table`) > 500 then 1 else 2 end
But this throws an error:
Select case when (Select count(*) as t from `table`) > 500 then (DELETE FROM table) else null end
1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'DELETE FROM table else null end LIMIT 0, 25' at line 1
I understand there is a syntax error, but my main question is why the case statement works when I place integers in the condition, but the delete statement throws an error. I tried a select statement and it worked fine:
Select case when (Select count(*) as t from `table`) < 500 then (select count(*) from table) else null end
If you really wanted to do this with a single delete:
delete t
from table t cross join
(select count(*) as cnt from table t) c
where c.cnt > 500;
Do note (as BWS does) that truncate table is more efficient, although you cannot use a where clause or join with truncate table
If you are trying to delete all the rows from the table, just use "TRUNCATE table"
The CASE statement works with SELECT when the SELECT statement produces a single value (i.e. it selects only one column and the result set has a single row); it doesn't work otherwise. Obviously, a DELETE (or INSERT, UPDATE etc) never works in that position.

Select IF EXISTS THEN ELSE on Mysql

I have tried to solve this issue a lot, checked a lot of sites, tried more examples, but did not get what I want yet.
My sql logic on my php Page like at below:
IF (EXISTS (SELECT * FROM suborders WHERE subId = 1))
THEN SELECT * FROM suborders WHERE subId = 1 //if exists just do this sql again
ELSE SELECT id FROM orders WHERE id = 1 LIMIT 1;
Mysql Gives an error on syntax at the first query. So, I also tried to use another way at below:
delimiter //
create procedure test()
begin
IF EXISTS (SELECT * FROM suborders WHERE subId = 1) THEN
SELECT * FROM suborders WHERE subId = 1;
ELSE
SELECT id FROM orders WHERE id = 1 LIMIT 1;
END IF;
end //
delimiter ;
call test();
Using 2nd query mysql returns empty result, without error. Actually, there should be something to fetch...
IF EXISTS (SELECT * FROM suborders WHERE subId = 1 )
BEGIN
SELECT * FROM suborders WHERE subId = 1
END
ELSE
BEGIN
SELECT id FROM orders WHERE id = 1 LIMIT 1
END
Full stored Procedure:
DELIMITER //
CREATE PROCEDURE sp_select_suborders(IN `p_subId`)
IF EXISTS (SELECT * FROM suborders WHERE subId = p_subId )
BEGIN
SELECT * FROM suborders WHERE subId = p_subId
END
ELSE
BEGIN
SELECT id FROM orders WHERE id = p_subId LIMIT 1
END //
DELIMITER ;
Usage:
$stmt = $db->prepare('CALL sp_select_suborders(?)');
Why don't you simple handle the case of no results in php?
$yourDBUsage->query("SELECT * FROM suborders WHERE subId = 1");
if ($yourDBUsage->count == 0){
$yourDBUsage->query("SELECT id FROM orders WHERE id = 1 LIMIT 1;");
}
Since suborders.subId is a foreign key referencing orders.id, you can approach your query logic with a single LEFT JOIN query. I would prefer this solution because it means you do not have to maintain a stored procedure separately. All the query logic is bundled with your application code.
By doing a LEFT JOIN from orders against suborders, columns from suborders may return NULL. In your application code, you may then test if they are null, and if they are, use the id from orders instead. This method essentially transfers the flow logic to your PHP code, while stuffing all the database actions into one query, which will either return one row, or many rows (or none, if the requested id doesn't exist in orders)
SELECT
orders.id AS orders_id,
suborders.*
FROM
orders
LEFT JOIN suborders ON orders.id = suborders.subId
WHERE orders.id = ?
In the PHP logic, execute that query with an appropriate value in place of ?. When fetching, you will be able to discern immediately if suborders has no return, as all the suborders columns will be NULL.
// Assume fetched into $orders
foreach ($orders as $order) {
if ($order['subId'] === null) {
// Use orders.id...
// If it is a unique id, this will be the only row
// and the loop will terminate here
echo $order['orders_id'];
}
else {
// subId has a value, so you can use the other suborders cols
echo $order['subId'];
echo $order['other_suborder_column'];
}
This way, if suborders does match and populate columns, you would be able to loop over the entire returned rowset, equivalent to SELECT * FROM suborders. Otherwise, you can break the loop right away (or if orders.id is unique as I suspect it is, it will only ever return one row anyway with an orders_id and null suborders).

Performing select operations with a cursor inside a caught exception

I'm trying to write a Stored Procedure which takes input of an ID then searches 3 different tables for that item using different criteria. One solution I have is to perform the select statement on each table one by one, and catching the NO_DATA_FOUND exception if nothing is found via the select.
In pseudocode:
Select item from from first table
If no data found, throw exception.
Handle exception by selecting data from second table
If no data found, throw another exception.
Handle exception by selecting data from third table (if the data is not present in any row it should return 0 rows)
Here's what I have:
OPEN REQUEST FOR
SELECT REQ_TYPE, REQ_TYPE_STATUS FROM TABLEONE
WHERE TABLEONE.REQ_ID = REQUESTID
AND (REQ_STATUS = 'D' OR REQ_STATUS = 'A');
EXCEPTION WHEN NO_DATA_FOUND THEN
BEGIN
OPEN REQUEST FOR
SELECT REQ_TYPE, '-' AS REQ_TYPE_STATUS FROM TABLETWO
WHERE TABLETWO.REQ_ID = REQUESTID;
EXCEPTION WHEN NO_DATA_FOUND THEN
begin
OPEN REQUEST FOR
SELECT REQ_TYPE, '-' as REQ_TYPE_STATUS FROM THIRDTABLE
WHERE THIRDTABLE.REQ_ID = REQUESTID;
end;
END;
If an item is found in TABLEONE, it successfully returns the data for it. However, the SELECT operations that are performed inside the caught exceptions don't seem to run as the the stored procedure doesn't return any rows.
I have separately verified that the data I'm searching for definitely exists in TABLETWO AND/OR TABLETHREE.
The syntax is valid as it compiles, it's just that it doesn't return any rows if the item doesn't exist in TABLEONE (but exists in either TABLETWO or TABLETHREE).
Any ideas?
Credit to #Franek for this.
The referenced linked article explains the following:
Cursor FOR loop is smart. It won't raise NO-DATA-FOUND as it is; if
there's nothing to be fetched, it will exit the loop and terminate
execution successfully. Therefore, if you meant to handle it as an
EXCEPTION - you can not.
What I was attempting to do is apparently not possible. Therefore, I have implemented it this way instead:
Pseudocode:
Search for the item in the first table
If item was found
select the details of it from the first table
If item was not found
search for the item in the second table
If Item was found
Select the details of it from the second table
If item was not found
Select the item from the third table (returning blank if it's not found here neither)
PL/SQL Implementation:
-- Search for the request ID in the first table
SELECT COUNT(REQ_ID) INTO requestFound FROM FIRSTTABLE
WHERE FIRSTTABLE.REQ_ID = REQUESTID
AND (REQ_STATUS = 'D' OR REQ_STATUS = 'A');
IF(REQUESTFOUND > 0) THEN
-- Select the request details
OPEN REQUEST FOR
SELECT REQ_ID, REQ_TYPE_STATUS FROM FIRSTTABLE
WHERE FIRSTTABLE.REQ_ID = REQUESTID
AND (REQ_STATUS = 'D' OR REQ_STATUS = 'A');
ELSE
-- Search for the request from the second table
SELECT COUNT(REQ_ID) INTO REQUESTFOUND FROM SECONDTABLE
WHERE SECONDTABLE.REQ_ID = REQUESTID;
IF(REQUESTFOUND > 0) THEN
-- Select the request details from second table
OPEN REQUEST FOR
SELECT REQ_TYPE, '-' AS REQ_TYPE_STATUS FROM SECONDTABLE
WHERE SECONDTABLE.REQ_ID = REQUESTID;
ELSE
-- Get the request from third table (will return as blank if nothing found)
OPEN REQUEST FOR
SELECT REQ_TYPE, '-' AS REQ_TYPE_STATUS FROM THIRDTABLE
WHERE THIRDTABLE.REQ_ID = REQUESTID;
END IF;
END IF;

MySQL update from select and further select and updates

Currently trying to find a way to do the following inside some form of loop (preferably without a performance hit on database).
I have 3 tables user_hours, user_calendar and hours_statistics. I need to first do:
SELECT user_calendar.date_start,
user_calendar.opportunity_id,
user_hours.user_id,
user_hours.agreed_hours,
user_hours.completed_hours,
user_hours.hours_committed
FROM user_calendar
JOIN user_hours
ON user_calendar.user_calendar_id = user_hours.user_calendar_id
WHERE user_calendar.date_start = CURRENT_DATE()
AND user_hours.completed_hours IS NULL
AND user_hours.hours_committed = 'accepted'
This query could return like the following:
http://i.imgur.com/5cJ5v.png
So for each opportunity_id and user_id returned i'd like to then do:
UPDATE user_hours
SET completed_hours = agreed_hours,
hours_committed = 'completed'
WHERE opportunity_id = {opportunity_id}
AND user_id = {user_id}
AND hours_committed = 'accepted'
AND completed_hours IS NULL
Note that {opportunity_id} and {user_id} would need to be looped at this point (see screenshot) because we need to go through each user on each opportunity.
Then for each updated record i'd need to then get the total hours like:
// Get hours they have done to send to statistics data table
SELECT sum(completed_hours) FROM user_hours WHERE user_id = {user_id} AND opportunity_id = {opportunity_id} 
// Get the completed hours total somehow as a variable
$completed_hours = (from result above)
// Commit stats
UPDATE hours_statistics SET completed_hours = (completed_hours+$completed_hours)
WHERE user_id = {user_id} AND opportunity_id =  {opportunity_id} 
Could anyone help write this as a procedure or a trigger of some kind or help me in the right direction to get a starting point for looping over this stuff? Manually the querying works, just need to be looped / automatic for a stats update to run.
You can create a trigger to update hours_statistics whenever user_hours is updated (you may also want to add similar triggers for INSERT and DELETE operations, depending on your application logic).
Assuming that a UNIQUE key has been defined on hours_statistics.(user_id, opportunity_id) one can use INSERT ... ON DUPLICATE KEY UPDATE within the trigger:
CREATE TRIGGER foo AFTER UPDATE ON user_hours FOR EACH ROW
INSERT INTO hours_statistics (user_id, opportunity_id, completed_hours) VALUES
(OLD.user_id, OLD.opportunity_id, -OLD.completed_hours),
(NEW.user_id, NEW.opportunity_id, +NEW.completed_hours)
ON DUPLICATE KEY UPDATE
completed_hours = completed_hours + VALUES(completed_hours);
Then you can use a single UPDATE statement (using the multiple-table syntax to join user_hours with user_calendar) to perform all of the updates on user_hours in one go, which will cause the above trigger to update hours_statistics as desired:
UPDATE user_hours JOIN user_calendar USING (user_calendar_id, opportunity_id)
SET user_hours.completed_hours = agreed_hours,
user_hours.hours_committed = 'completed'
WHERE user_hours.hours_committed = 'accepted'
AND user_hours.completed_hours IS NULL
AND user_calendar.date_start = CURRENT_DATE();

Resources