Assigning a value from another database and function - MySQL variable scope - mysql

I am using MySQL to make a report showing the number of hours billed for a particular date range and project. The complexity is that the date range is variable for each project (different start month and start day). This information is coming from a value in another database/table.
I have the following UDF in MySQL:
DELIMITER //
CREATE FUNCTION TimeLeft(startday INT, today INT) RETURNS INT
DETERMINISTIC
BEGIN
DECLARE s INT;
IF startday < today THEN SET s = 0;
ELSE SET s = 1;
END IF;
RETURN s;
END //
DELIMITER;
I use that function in the following query, which is supposed to take the value returned in the TimeLeft function to determine the values for the start month (month(curdate())-#xx) and start day (#yy) for each project to calculate the hours:
AND time_records.record_date >= concat('2012/', month(curdate())-#xx , '/' , #yy)
Here's how I am setting the values for #xx and #yy:
SET #xx = 0; #this is the value that we will use to manipulate the month for the date range
SET #yy = 0;
#yy:= SELECT start_day_of_month FROM dashboard.client; #this doesn't seem to work
SELECT #xx:= TimeLeft(#yy,dayofmonth(curdate()));
I am getting some issues:
#yy is not getting the value - possibly my syntax is wrong?
The variables are set at the top of the code, so they are not getting changed for each project as they should be (there should be a different #xx and #yy for each project since each one has a different start and end date).
Here's the full query:
#below is where I assign the variables
SET #xx = 0; #this is the value that we will use to manipulate the month for the date range
SET #yy = 0;
#yy:= SELECT start_day_of_month FROM dashboard.client; #this doesn't seem to work
SELECT #xx:= TimeLeft(#yy,dayofmonth(curdate()));
# below is the MySQL query that is meant to use the variables assigned above
SELECT X.expr1 AS 'Project Name', #monthly_hours - SUM(X.expr2) AS 'Hours Billed
FROM
(SELECT
projects.name AS expr1
, sum(time_records.value) AS expr2
FROM project_objects
INNER JOIN projects
ON projects.id = project_objects.project_id
INNER JOIN time_records
ON time_records.parent_id = project_objects.id
WHERE time_records.parent_type = 'Task'
AND time_records.record_date >= concat('2012/', month(curdate())-#xx , '/' , #yy)
AND time_records.record_date <= curdate()
GROUP BY projects.name
UNION
SELECT
projects.name AS expr1
, sum(time_records.value) as expr2
FROM projects
INNER JOIN time_records
ON projects.id = time_records.parent_id
WHERE time_records.parent_type = 'Project'
AND time_records.record_date >= concat('2012/', month(curdate())-#xx , '/' , #yy)
AND time_records.record_date <= curdate()
GROUP BY projects.name) X
GROUP BY X.expr1
I think there is some issue of where I am assigning the variables #xx and #yy. These should be done for each individual Project, so putting them up on the top is probably not the best idea. I'm also not sure if I am assigning the #yy value correctly. It's supposed to query the value of the field of a table that is in another database but it keeps throwing a syntax error on the #yy assignment to that field.

Assign value to #yy inside select:
SELECT #yy:= start_day_of_month FROM dashboard.client;

Related

I am building my first function in PLSQL, it needs to return a single summed value of spending by a user based off parameters username and fiscal year

The function compiles, but when I run this block:
select sumyUserSpending('ALCraft', 15) from infor.credit_card_transaction
It throws error ORA-06575: Package or function sumyuserspending is in an invalid state.
When I run this block:
declare
answer number;
begin
answer := sumyUserSpending('ALCraft', 15);
dbms_output.put_line(answer);
end;
It throws errors ORA-65550 and PLS-00905: object sumyuserspending is invalid.
Here is my function. When I only run the function, it throws no errors, so I am lost as to what it could need to run smoothly. When the query is taken out of the function and I run the query alone, it returns the value I want based on the placeholder values I put in for the parameters. I am working in oracle 12c.
create or replace function sumyUserSpending (userN in varchar2, fiscYear in number)
return number
is
total number;
cursor search1 is
select sum(infor.credit_card_transaction.due_cc_co_amount) into total from infor.credit_card_transaction
inner join infor.credit_card using (credit_card_id)
inner join infor.ext_user using (user_id)
where infor.credit_card_transaction.transaction_date > concat('01-JUL-', (fiscYear - 1))
and infor.credit_card_transaction.transaction_date < concat('30-JUNE-', fiscYear)
and NVL(SUBSTR(infor.ext_user.email_address, 0, INSTR(infor.ext_user.email_address, '#')-1), infor.ext_user.email_address) = userN;
begin
open search1
fetch search1 into total;
if search1%notfound then
total := 0;
end if;
close search1;
return total;
end;
You need to refer to the tables by their just table name or an alias outside the FROM clause and not by schema_name.table_name.
Do not rely on implicit conversion of strings to dates; explicitly convert them using TO_DATE.
If you are using a cursor then a INTO clause is not syntactically valid.
However, you do not need a cursor.
Fixing all that gives you:
create or replace function sumyUserSpending (
userN in ext_user.email_address%TYPE,
fiscYear in number
) RETURN number
IS
total number;
BEGIN
select COALESCE(sum(cct.due_cc_co_amount), 0)
into total
from infor.credit_card_transaction cct
inner join infor.credit_card cc using (credit_card_id)
inner join infor.ext_user eu using (user_id)
where cct.transaction_date >= TO_DATE((fiscyear - 1) || '07-01', 'RR-MM-DD')
and cct.transaction_date < TO_DATE(fiscyear || '07-01', 'RR-MM-DD')
and NVL(SUBSTR(eu.email_address, 0, INSTR(eu.email_address, '#')-1), eu.email_address)
= userN;
return total;
end;
/
db<>fiddle here

MySQL - str_to_date() not working in update query

I am trying to perform some calculations and update the table with the calculated value using SQL query. The query used is as follows:
UPDATE `table1` pv inner join
(SELECT Email,IF(`DS Start Date` = "-",Round((DATEDIFF(CURDATE(),STR_TO_DATE(`Start Date`,'%Y-%m-%d')))/365,2),
Round((DATEDIFF(STR_TO_DATE(`DS Start Date`,'%Y-%m-%d'),STR_TO_DATE(`Start Date`,'%Y-%m-%d')))/365,2)) as ba_tenure,
IF(`DS End Date` != "-",Round((DATEDIFF(STR_TO_DATE(`DS End Date`,'%Y-%m-%d'),STR_TO_DATE(`DS Start Date`,'%Y-%m-%d')))/365,2),
Round((DATEDIFF(CURDATE(),STR_TO_DATE(`DS Start Date`,'%Y-%m-%d')))/365,2)) as ds_tenure,
Round((DATEDIFF(CURDATE(),STR_TO_DATE(`Start Date`,'%Y-%m-%d')))/365,2) as overall_tenure
from `table1` where Status = "Active" ) A on (pv.Email = A.Email)
set pv.`Tenure (Yrs)` = A.overall_tenure,pv.`BA Team Tenure` = A.ba_tenure,pv.`DS Team Tenure` = A.ds_tenure
When I execute the select statement, the query runs good. But when I execute the update query it throws the error
#1411 - Incorrect datetime value: '-' for function str_to_date
I cannot figure out the issue. Can anyone help me to solve this issue?
If your second if you have DS Start Date for true and false but for false this mean that DS Start Date is equal to '-' and this value is not valid for str_to_date
IF(`DS End Date` != "-",
Round((DATEDIFF(STR_TO_DATE(`DS End Date`,'%Y-%m-%d'),STR_TO_DATE(`DS Start Date`,'%Y-%m-%d')))/365,2),
Round((DATEDIFF(CURDATE(),STR_TO_DATE(`DS Start Date`,'%Y-%m-%d')))/365,2)) as ds_tenure,

Write to database from case results

I want to update a databased based upon results from a case, however my "If" statement doesn't seem to pull information from the right table.
declare #dt datetime
set #dt = GETDATE()
select
Ugenummer = datepart(wk, #dt) - datepart(wk,dateadd(m, DATEDIFF(M, 0, #dt), 0)) + 1,
case when (datepart(wk, #dt) - datepart(wk,dateadd(m, DATEDIFF(M, 0, #dt), 0)) + 1) % 2 = 1
then 'ulige' else 'lige' end Ugelighed;
The above code gets the weeknumber (ugenummer) and determines whether it's odd or even (Ulige/lige)
IF Ugelighed = ulige and datepart(dw,#dt) = 1
THEN
UPDATE laeger
SET Antal=1
WHERE Navn=Lægenavn
I would like to use the information from the first code to update a database in a SQL 2008 server
You aren't using Ugenummer so I edited it out. Also created a variable for Ugelighed, you forgot to create one:
declare #dt datetime
set #dt = GETDATE()
declare #Ugelighed VARCHAR(5);
select
#Ugelighed=case when (datepart(wk, #dt) - datepart(wk,dateadd(m, DATEDIFF(M, 0, #dt), 0)) + 1) % 2 = 1
then 'ulige' else 'lige' end;
In the following statements I used variable #Ugelighed to compare to ulige however it is a VARCHAR so you need to enclose it in single quotes (''). Same for Lægenavn, it is a VARCHAR so enclose it in single quotes:
IF #Ugelighed = 'ulige' and datepart(dw,#dt) = 1
UPDATE laeger
SET Antal=1
WHERE Navn='Lægenavn'
Personally I would have created a BIT field for #Ugelighed since even/odd can be captured as a simple boolean rather than text.

How to use between operator for 2 date input parameters in mysql?

My task is to get the records between 2fromdate and todate(given as a input parameters).
i am not able to use between operator for 2 input parameters...
My query as follows...
DELIMITER $$
CREATE DEFINER=`testrunner`#`%` PROCEDURE `usp_GetAllTranasactions`(pFromDate nvarchar(30),pToDate nvarchar(30),pstatus int)
BEGIN
select
ST.UserID,U.Username,
ST.SubscriptionID,
ST.DateOfSubscription,
SM.SubType,
SM.Details,
ST.Amount,
ST.EndDate,
ST.Status
from tr_t_subscriptiontransactions ST
Join tr_m_users U on U.UserID=ST.UserID
join tr_m_subscription SM on SM.SubscriptionID=ST.SubscriptionID
where **ST.DateOfSubscription between (pFromDate and pToDate) and ST.EndDate
between(pFromDate and pToDate) and ST.Status=pstatus;**
END if;
END
here i don't know how to use between parameters..plz help me..i want to retrive record between fromdate and todate..hope u understand..
Let us assume you want all transactions for the month of June 2014
In your user interface the parameter values are:
from_date = 2014-06-01
to_date = 2014-06-30
But you will evaluate against a transaction date & time. How do you ensure that absolutely every transactions on June 30 - right up to midnight - is included in the results?
Here is how: use 2014-07-01 instead of 2014-06-30, and here is what the query would look like - which does NOT use between!
SELECT
ST.UserID
, U.Username
, ST.SubscriptionID
, ST.DateOfSubscription
, SM.SubType
, SM.Details
, ST.Amount
, ST.EndDate
, ST.Status
FROM tr_t_subscriptiontransactions ST
JOIN tr_m_users U
ON U.UserID = ST.UserID
JOIN tr_m_subscription SM
ON SM.SubscriptionID = ST.SubscriptionID
WHERE (ST.DateOfSubscription >= pFromDate AND ST.DateOfSubscription < pToDate + 1)
AND (ST.EndDate >= pFromDate AND ST.EndDate < pToDate + 1)
AND ST.Status = pstatus
;
AVOID between for date ranges because it INCLUDES both the lower and upper boundary values.
... equivalent to the expression (min <= expr AND expr <= max)
http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#operator_between
What this can lead to is an "anti-pattern" which look like this:
where dt_field between '2014-06-01 00:00:00' and '2014-06-30 23:59:59'
but there are time units smaller than one second, so that approach is imperfect. Don't attempt to overcome the deficiencies of between by adjusting the upper value this way. The simple and more accurate approach is to use >= and < adjusting the upper value by one whole time unit (usually the next day).

Mysql assign a single column value to a declared value using Select case

I am stucked with following issue,
I ve delcared a varibale (DOUBLE) in a stored procedure, and i need to assign a value (item price) from a table (item) to this declared variable. however, i need to get this value from a select query which uses case inside, the item price could be in 2 columns based on a logic i have to find the correct item price. Please help me solve this as when i execute it gives me a error,
Here how is layered,
DECLARE no_more_users INT DEFAULT 0;
DECLARE user_id INT DEFAULT 0;
DECLARE cart_id INT DEFAULT 0;
DECLARE cart_item_id INT DEFAULT 0;
DECLARE user_gift_id INT DEFAULT 0;
DECLARE itemPrice DOUBLE DEFAULT 0.0;
SELECT
CASE
WHEN sale_price=0 OR sale_price IS NULL THEN (price - ( price * discount ))
ELSE sale_price
END
INTO itemPrice
FROM item WHERE item_id = p_item_id ;
DECLARE checked_in_users CURSOR FOR
SELECT DISTINCT ul.user_id
FROM user_location ul
LEFT JOIN location_section ls ON ul.location_section_id = ls.location_section_id
INNER JOIN user u ON ul.user_id = u.user_id
INNER JOIN user_profile up ON u.user_id = up.user_id
INNER JOIN location_event le ON ul.location_event_id = le.location_event_id
WHERE ul.location_id = p_location_id AND ul.location_event_id = p_event_id
AND ul.checked_out_on IS NULL AND (ul.checked_in_on BETWEEN le.start_time AND le.end_time )
AND u.status = 1 ;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_users = 1;
OPEN checked_in_users;
FETCH checked_in_users INTO user_id;
read_loop: LOOP
some more code...
please note, sale_price, price, and discount are coulmns of item table, The logic is if sale_price is null or value is 0, then i actual sale price should be obtained from price coulmn. Finally what i need is asign corect item price in to previously declared varibale.
Any help will be highly appriciated.
There are two foms to the CASE statement, one with expressions and one with values. You are mixing them up.
with values:
CASE variable
WHEN value_1 THEN foo
WHEN value_2 THEN bar
END
with expressions:
CASE
WHEN expression_1 THEN foo
WHEN expression_2 THEN bar
END
Try
CASE
WHEN sale_price=0 OR sale_price IS NULL THEN (price - ( price * discount ))
ELSE sale_price
END
Also, you do not need the "AS correct_price" when you are using an INTO
Your select query has some problems.
The version of CASE you are are using - ie CASE var WHEN val1 THEN - doesn't work when trying to match a NILL, because in SQL null is not equal to null.
Also, you can't combine values with conditions as you hAve.
Instead, use the version if CASS that simply conditions. There are other suntactic problems. Converting your broken query then gives:
SELECT
CASE
WHEN ifnull(sale_price, 0) = 0 THEN price - (price * discount)
ELSE sale_price
END
INTO itemPrice
FROM item
WHERE item_id = p_item_id;
Note: if your table has s column called itemPrice, you must choose another name from your variable. Mysql gets confused :/