Less than date value in Stored Procedures is not working - mysql

I have couple of tables
Movements
Entries
and want to get the stock balance of items up to a given date. So I created queries and INNER JOINED to make a single table so it is easy to get the balance. This program is saved in a SP called
StblAsAt(IN RefDate DATE,IN Store VARCHAR,OUT #STBL DOUBLE)
However when I user the date format in the body as appears in the following line it works fine.
purchaseinvoice.invoiceDate<='2021-08-30'
But when it is changed to use the parameter, it returns zero (0). No matter what date I pass.
This is my code as it is in Stored Procedure
BEGIN
SELECT (Purchase+SalesReturns+TransferIn)-(PurchaseReturns+Sales+TransferOut) INTO #STBL FROM(
SELECT COALESCE(P.Purchase,0)AS 'Purchase',
COALESCE(Sr.SalesReturn,0)AS 'SalesReturns',
COALESCE(Ti.TransferIn,0)AS 'TransferIn',
COALESCE(Pr.PurchaseReturns,0)AS 'PurchaseReturns',
COALESCE(S.Sales,0) AS 'Sales',
COALESCE(Tout.TransferOut,0)AS 'TransferOut'
FROM(
(SELECT
'OTHRMA1032' AS 'Item',
SUM(movement.itemQty) AS 'Purchase'
FROM movement
WHERE
movement.movementType=0 AND
movement.entryDate<=DATE_FORMAT(#RefDate,'%Y-%m-%d')AND #Tried #RefDate and it fails
movement.itemId='OTHRMA1032' AND
movement.reference2 IN(
SELECT purchaseinvoice.GRNId
FROM purchaseinvoice
WHERE
purchaseinvoice.invoiceDate<=DATE_FORMAT(#RefDate,'%Y-%m-%d') AND
purchaseinvoice.inwardStore='Main store'
))P
(Didn't include all queries as it would make the post junk)
This is how I call the procedure from MySql
CALL StblAsAt('2021-08-30','Main store',#STBL);
Whenever the parameter is used, it returns zero and when the date is typed in, it returns the correct value.

Related

"Column Count Doesn't Match Value at row." Missing t_stamp which is auto generated

My issue is that I am using a stored procedure to copy everything from one table into a new table and in the new table. I am also auto generating a timestamp column in the new table. I know the issue has to do with this t_stamp column. I just don't know how to handle that. Here is my code in the stored procedure: Both tables will be exactly the same except the new table will have a t_stamp column just to keep track of the date. The reason i created the second table is the first one gets cleared every day while the second one is need to keep record.
CREATE DEFINER="root"#"localhost" PROCEDURE "backupSAPTables"()
BEGIN
INSERT INTO sap.process_order_confirmation_detail_backup
SELECT ProcessOrder, ConfirmationSeq, Material, ByProductIndicator, Quantity, UOM, Batch, MovementType, ManufDate, GI_GR_Indicator, GMP_Indicator, GMP_Production_Date, GMP_Production_Time, GMP_Fat, GMP_Fat_UOM, GMP_Protein, GMP_Protein_UOM, GMP_Total_Solids, GMP_Total_Solids_UOM, FillerName, ChangedDate, ChangedTime, ChangedBy
FROM sap.process_order_confirmation_detail
WHERE NOT EXISTS(SELECT ProcessOrder, ConfirmationSeq, Material, ByProductIndicator, Quantity, UOM, Batch, MovementType, ManufDate, GI_GR_Indicator, GMP_Indicator, GMP_Production_Date, GMP_Production_Time, GMP_Fat, GMP_Fat_UOM, GMP_Protein, GMP_Protein_UOM, GMP_Total_Solids, GMP_Total_Solids_UOM, FillerName, ChangedDate, ChangedTime, ChangedBy
FROM sap.process_order_confirmation_detail_backup
WHERE (sap.process_order_confirmation_detail.ProcessOrder = sap.process_order_confirmation_detail_backup.ProcessOrder and sap.process_order_confirmation_detail.ConfirmationSeq = sap.process_order_confirmation_detail_backup.ConfirmationSeq and sap.process_order_confirmation_detail.Material = sap.process_order_confirmation_detail_backup.Material));
END
If you don't provide all columns of the target table for insert, then you need to enumerate all of the target columns in the insert clause, so it is explicit which value should be assigned to which column. The database will then assign the relevant value to the "missing" columns (default if there is one, else null).
You stated that the structures of the tables are the same (apart from the auto-generated timestamp column), so that should be:
INSERT INTO sap.process_order_confirmation_detail_backup (
ProcessOrder,
ConfirmationSeq,
Material,
ByProductIndicator,
Quantity,
UOM,
Batch,
MovementType,
ManufDate,
GI_GR_Indicator,
GMP_Indicator,
GMP_Production_Date,
GMP_Production_Time,
GMP_Fat,
GMP_Fat_UOM,
GMP_Protein,
GMP_Protein_UOM,
GMP_Total_Solids,
GMP_Total_Solids_UOM,
FillerName,
ChangedDate,
ChangedTime,
ChangedBy
)
SELECT
ProcessOrder,
ConfirmationSeq,
Material,
ByProductIndicator,
Quantity,
UOM,
Batch,
MovementType,
ManufDate,
GI_GR_Indicator,
GMP_Indicator,
GMP_Production_Date,
GMP_Production_Time,
GMP_Fat,
GMP_Fat_UOM,
GMP_Protein,
GMP_Protein_UOM,
GMP_Total_Solids,
GMP_Total_Solids_UOM,
FillerName,
ChangedDate,
ChangedTime,
ChangedBy
FROM sap.process_order_confirmation_detail
WHERE ...

MySQL Select into variable not working always

I am facing a strange behavior.
SELECT INTO and SET Both works for some variables and not for others. Event syntaxes are the same.
SET #Invoice_UserId := (SELECT UserId FROM invoice WHERE InvoiceId = #Invoice_Id LIMIT 1); -- Working
SET #myamount := (SELECT amount FROM invoice WHERE InvoiceId = #Invoice_Id LIMIT 1); - Not working
SELECT Amount INTO #myamount FROM invoice WHERE InvoiceId = 29 LIMIT 1; - Not working
If I run these queries directly then works, but not working in the stored procedure.
All of the syntaxes are valid and will work (apart from the invalid comment - which should be --.
If you have a problem, please post the full stored procedure.
In the stored procedure you should use local variables (DECLARE var) instead of user defined variables (#var) as local variables are strongly typed and have scope of the routine.

Executing query through pymysql not returning the same results as running in MySQL

I'm new to Python and PyMySQL, so I may have something misconfigured.
I'm connecting to MySQL without any problems. I tested it doing a SELECT and a DESC on a table, and was able to view the results.
I now have a query that I substitute date parameters into and want returned the count of a column (customers) and the total number of customers multiplied times a value.
The count of customers comes back correctly, but the product calculation returns None. Before executing the query, I print it to the console and copy that to MySQLWorkbench to run, and the correct values are returned.
In my main module I connect to the DB and get a cursor. I then get date values to use in the query and call the function that executes the query.
connection = dbConnection()
cursor = connection.cursor()
startDate = input("enter start date (yyyy-mm-dd): ").strip()
endDate = input("enter end date (yyyy-mm-dd): ").strip()
my_queries.queryTotals(cursor, startDate, endDate)
connection.close()
In my my_queries module I have the query and substitute the entered dates into the query string, then execute the query and fetch the results:
totalsSQL = '''select
#total:=count(cus.customer_id) as customers, format(#total * 1.99, 2) as total
from customer cus
join membership mem on mem.membership_id=cus.current_membership_id
where mem.request='START'
and (mem.purchase_date > (unix_timestamp(date('{}'))*1000) and mem.purchase_date < unix_timestamp(date('{}'))*1000);'''
formattedSQL = totalsSQL.format(startDate, endDate)
cursor.execute(formattedSQL)
result = cursor.fetchone()
I get a result of (32, None) as opposed to getting a numeric value for the 2nd column value.
What am I missing here?
Thanks.
You can't use a variable for an aggregate function, and refer to it later in the same SELECT list. Aggregates don't get their values until all the rows have been selected, but other columns are calculated while selecting rows.
Just use COUNT(*) in both places.
SELECT COUNT(*) AS customers, FORMAT(COUNT(*) * 1.99, 2) AS total
join membership mem on mem.membership_id=cus.current_membership_id
where mem.request='START'
and (mem.purchase_date > (unix_timestamp(date('{}'))*1000)
and mem.purchase_date < unix_timestamp(date('{}'))*1000)
Also, to prevent SQL injection you should use a parametrized query instead of substituting variables with format().
totalsSQL = '''
SELECT COUNT(*) AS customers, FORMAT(COUNT(*) * 1.99, 2) AS total
join membership mem on mem.membership_id=cus.current_membership_id
where mem.request='START'
and (mem.purchase_date > (unix_timestamp(date(%s))*1000)
and mem.purchase_date < unix_timestamp(date(%s))*1000)
'''
cursor.execute(totalsSQL, (startDate, endDate))

MS Access QUERY: Date Parameter criteria on calculated date field

I have a query that attaches dates to records, and I want the query to only return records whose newly attached dates are within the range of my input parameters.
In the Criteria block:
Between [StartDate] And [EndDate] does not work.
while...
Between #6/1/17# And #10/1/17# does work.
I assume it has to be a formatting issue, but don't know where to go from here. How can I marry the two (my calculated date and the input date parameters) fields so they compare correctly?
The SQL follows, I've copied the http://www.allenbrowne.com/ser-62.html sample database with plans to tweak it as needed.
PARAMETERS StartDate DateTime, EndDate DateTime;
SELECT qryCoreEventCartesian.EventID, qryCoreEventCartesian.InstanceID, DateAdd([qryCoreEventCartesian]![PeriodTypeID],[qryCoreEventCartesian]![InstanceID]*[qryCoreEventCartesian]![PeriodFreq],[qryCoreEventCartesian]![BeginDate]) AS EventDate, qryCoreEventCartesian.PID, qryCoreEventCartesian.Type, qryCoreEventCartesian.Comments, qryCoreEventCartesian.BeginDate, qryCoreEventCartesian.RecurCount, qryCoreEventCartesian.PeriodFreq, qryCoreEventCartesian.PeriodTypeID
FROM ltPeriodType INNER JOIN qryCoreEventCartesian ON ltPeriodType.PeriodTypeID = qryCoreEventCartesian.PeriodTypeID
WHERE (((DateAdd([qryCoreEventCartesian]![PeriodTypeID],[qryCoreEventCartesian]![InstanceID]*[qryCoreEventCartesian]![PeriodFreq],[qryCoreEventCartesian]![BeginDate])) Between [StartDate] And [EndDate]))
ORDER BY DateAdd([qryCoreEventCartesian]![PeriodTypeID],[qryCoreEventCartesian]![InstanceID]*[qryCoreEventCartesian]![PeriodFreq],[qryCoreEventCartesian]![BeginDate]);

SQL Server Stored Procedure Email verification

I have an ASP.net that requests client's information from stored procedure in SQL Server 2008 based on a client's email address until the # sign. Since the clients often change after 3 months in this small organization, but the email addresses remain the same.
E.g. a client with email address obois_in4#cegepoutaouais.qc.ca finishes his/her contract after 3-4 months and then that email address is assigned to someone else.
Now, here's my question: I want my stored procedure to find the client information, after he/she entered obois_in4 and presses the Search button. The reason I don't want them to enter the whole email is because it's too long, and secondly they can make a mistake while typing, but typing such as obois_in4 isn't a big deal.
I wrote a code that can search a client by name, but again, the clients always change after 3-4 months but the email address remains the same.
ALTER PROCEDURE [dbo].[sp_find_client_information]
-- Add the parameters for the stored procedure here
#client_email varchar (50) = null
AS Declare #numOfRows int BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT #numOfRows = COUNT (*)
From helpdesk_clients
Where --change first name and
client_firstName = #client_email or client_lastName = #client_email;
begin
if (#numOfRows = 0)
select #numOfRows;
else if (#numOfRows = 1)
select
client_id,
client_firstName,
client_lastName,
client_work_email,
client_work_phone,
client_work_phone_ext,
client_office,
dept_nom,
client_position
from
helpdesk_clients join departments
on
helpdesk_clients.dept_id = departments.dept_id
where client_firstName like '%'+#client_email+'%';
end
END
The email address always starts with obois followed by an underscore _ then the name of the department information technology as in and then by a digit such as 4 in this case. e.g. obois_in4#cegepoutaouais.qc.ca
I am surprised nobody even bothered looking into this. The best solution is to use Substring() and CharIndex()
With SUBSTRING ( expression ,start , length ) we can truncate the string starting from a position within the string until a specified position within a string. With CHARINDEX ( expressionToFind ,expressionToSearch [ , start_location ] ), we can find the the position of a character within a given string.
substring (work_email, 1, CHARINDEX('#', work_email)-1) = #work_email ensures that a parameter doesn't have to be like shawn.smith#cegepoutaouais.qc.ca, and it's a big hassle for a client to enter his full email like shawn.smith#cegepoutaouais.qc.ca, he will only be required to enter shwan.smith, the script will search for shawn.smith in shawn.smith#cegepoutaouais.qc.ca until the # sign.
e.g.
In the stored procedure, assuming the #work_email is parameter and it's value is 'shawn.smith'
select
client_id,
client_firstName,
client_lastName,
client_work_email,
client_work_phone,
client_work_phone_ext,
client_office,
dept_nom,
client_position
from
helpdesk_clients join departments
on
helpdesk_clients.dept_id = departments.dept_id
where substring (work_email, 1, CHARINDEX('#', work_email)-1) = #work_email;
Will return the all the details mentioned in the Select statement.