VB.Net Daily Time Record MySQL - mysql

Good day, I have a problem regarding MySQL queries. I want to create a daily time record output but my problem is on making queries. What I want is that when a record have the same id and date it must be updated otherwise it will insert a new record. These are some of screenshots of table properties

CREATE PROCEDURE dbo.EditGrade
#Id int
,#TimeIn datetime
,#TimeOut datetime
,#Existing bit OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #CurrentTimeIn as datetime
DECLARE #CurrentId as int
SELECT #CurrentId = Id
FROM tblAttendance
WHERE TimeIn = #TimeIn
IF (#CurrentId <> #Id)
BEGIN
IF (SELECT COUNT(ISNULL(Id,0))
FROM tblAttendance
WHERE TimeIn = #TimeIn
SET #Existing = 0
ELSE
SET #Existing = 1
END
ELSE
BEGIN
SET #Existing = 0
END
IF #Name = ''
SET #Name = null
IF (#Existing = 0)
UPDATE tblAttendance
SET TimeIn = #TimeIn
--other column values here
WHERE Id = #Id
ELSE
--INSERT FROM tblAttendance query here
END
GO
this is from stored procedure of ms sql, you can just convert it into mysql version.
take note, datetime types also checks the seconds, so don't include the seconds as much as possible or it will render as NOT THE SAME (e.g time in = 10:00:01 and time out is 10:00:02 will be rendered as NOT THE SAME)

Related

All Tables cant' perform INSERT OR UPDATE

I used a stored procedure that uses a cursor to loop through and process an attendance data table on Mariadb 10.1 database after calling the procedure the first time all the tables on the database lost the ability to perform INSERT INTO or UPDATE statements unless the targeted table is truncated first, can any one tell me what went wrong and how to fix it
the procedure that caused the problem:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `settle_attendance`()
MODIFIES SQL DATA
BEGIN
DECLARE trans_done BOOLEAN DEFAULT FALSE;
DECLARE punchid BIGINT(20);
DECLARE timein DATETIME;
DECLARE utctimein DATETIME;
DECLARE timeout DATETIME;
DECLARE utctimeout DATETIME;
DECLARE inday DATE;
DECLARE outday DATE;
DECLARE todaysdate DATE;
DECLARE attendcur CURSOR FOR
SELECT id, punch_in_utc_time, punch_in_user_time,
punch_out_utc_time, punch_out_user_time
FROM ohrm_attendance_record
ORDER BY id ASC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET trans_done = TRUE;
OPEN attendcur;
edit_loop: LOOP
SET todaysdate = CURRENT_DATE();
FETCH attendcur INTO punchid, utctimein, timein, utctimeout, timeout;
IF trans_done THEN
CLOSE attendcur;
LEAVE edit_loop;
END IF;
SET inday = DATE(timein);
SET outday = DATE(timeout);
SET todaysdate = CURRENT_DATE();
IF (inday < todaysdate) OR (outday < todaysdate) THEN
CASE
WHEN (timein IS NULL OR timein = '')
OR (utctimein IS NULL OR utctimein = '') THEN
UPDATE ohrm_attendance_record
SET punch_in_utc_time = utctimeout,
punch_in_user_time = timeout,
state = 'PUNCHED OUT'
WHERE punchid = id;
ELSE BEGIN END;
END CASE;
CASE
WHEN (timeout IS NULL OR timeout = '')
OR (utctimeout IS NULL OR utctimeout = '') THEN
UPDATE ohrm_attendance_record
SET punch_out_utc_time = utctimein,
punch_out_user_time = timein,
state = 'PUNCHED OUT'
WHERE punchid = id;
ELSE BEGIN END;
END CASE;
END IF;
END LOOP edit_loop;
END $$
DELIMITER ;
I choose to avoid the question you asked. Instead, let's try to do the query 10 times as fast by getting rid of the pesky CURSOR. The entire Stored Procedure can be done in 2 UPDATEs, no loop:
UPDATE ohrm_attendance_record
SET punch_in_utc_time = utctimeout,
punch_in_user_time = timeout,
state = 'PUNCHED OUT'
WHERE ( timein < CURDATE() OR timeout < CURDATE() )
AND ( ( timein IS NULL OR timein = '' )
OR ( utctimein IS NULL OR utctimein = '' )
);
UPDATE ohrm_attendance_record
SET punch_out_utc_time = utctimein,
punch_out_user_time = timein,
state = 'PUNCHED OUT'
WHERE ( timein < CURDATE() OR timeout < CURDATE() )
AND ( ( timeout IS NULL OR timeout = '' )
OR ( utctimeout IS NULL OR utctimeout = '' )
);
I am, however, suspicious of your tests against timein and timeout.
The queries would be easier to read if you settled on either NULL or '' for missing times.
If you store only UTC values in a TIMESTAMP, you can let the user's timezone take care of coverting to local time -- this would eliminate quite a few columns and simplify the UPDATEs.
I'll make a stab at the question... Do SHOW CREATE PROCEDURE settle_attendance;, you may find that the CHARACTER SET or COLLATION is inconsistent with what you think it should be.

what's wrong with this if/then stored proc?

I'm fuzzy on when I need you use # to reference vars in mySQL. I'm coming from MS SQL where you always use it, but apparently that's not correct in mySQL.
So the below stored procedure is always executing the first IF block, even if the session value is expired - in that it's always executing the update statement. Apparently the only debug tool I could find for mySQL stored procs runs on Windows and Linux. I'm on a Mac. Wamp wamp wamp.
So yeah. Can anyone see what's wrong here? Thanks!
DELIMITER $$
CREATE DEFINER=`xxx`#`localhost` PROCEDURE `validate_session`(uid INT, token VARCHAR(256))
BEGIN
DECLARE sessId INT DEFAULT NULL;
SELECT sessId = id FROM UserSessions
WHERE userId = uid
AND sessionToken = token
AND expires > INTERVAL 2 MINUTE + NOW() ORDER BY expires DESC LIMIT 1;
IF sessId IS NOT NULL THEN
UPDATE UserSessions
SET expires = INTERVAL 2 HOUR + NOW()
WHERE id = sessId;
ELSE
DELETE FROM UserSessions
WHERE userId = uid
AND sessionToken = token;
SET #sessId = 0;
END IF;
SELECT sessId;
END
For the record what it's supposed to do in pseudo code:
if we have a session for this user, with a matching token which has not expired {
update the expiration time to 2 hours from now
return the session id;
}
else {
delete the (now stale) session
return 0;
}
Thanks in advance.
You're not setting the value of sessId... you're making a comparisson in your query.
I think what you need is something like this:
CREATE DEFINER=`xxx`#`localhost` PROCEDURE `validate_session`(uid INT, token VARCHAR(256))
BEGIN
DECLARE sessId INT DEFAULT NULL;
SELECT id
INTO sessId -- Here is the assignment
FROM UserSessions
WHERE userId = uid
AND sessionToken = token
AND expires > INTERVAL 2 MINUTE + NOW()
ORDER BY expires DESC
LIMIT 1;
IF sessId IS NOT NULL THEN
UPDATE UserSessions
SET expires = INTERVAL 2 HOUR + NOW()
WHERE id = sessId;
ELSE
DELETE FROM UserSessions
WHERE userId = uid
AND sessionToken = token;
SET sessId = 0;
END IF;
SELECT sessId;
END
Reference:
MySQL Reference: SELECT ... INTO syntax
MySQL Reference: Local variable scope and resolution

MySQL AUTO INCREMENT with Prefix (YYMM) that reset every month

I saw another post explaining the use of sequence table to create prefixed AUTO INCREMENT ID.
Link to referenced post
SQL Fiddle
http://sqlfiddle.com/#!2/0ed88/1
I need the generated auto increment format to be: YYMM + AUTO INCREMENT VALUE that reset every month. For example now is January, 2015. The generated id should be: 15011, 15012, 15013, etc. Next month February 2015, the generated id should be: 15021, 15022, 15023, etc. I can use the above method to generate the prefix, however how do I reset the AUTO INCREMENT value each month? Database is InnoDB. Any help will be greatly appreciated :)
MODIFIED CODE
CREATE TABLE table1_seq
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
)|
CREATE TABLE Table1
(
id VARCHAR(7) NOT NULL PRIMARY KEY DEFAULT '0', name VARCHAR(30)
)|
CREATE TRIGGER tg_table1_insert
BEFORE INSERT ON table1
FOR EACH ROW
BEGIN
INSERT INTO table1_seq VALUES (NULL);
SET NEW.id = CONCAT(DATE_FORMAT(NOW(),'%y%m'), LAST_INSERT_ID());
END |
INSERT INTO Table1 (name) VALUES ('Jhon'), ('Mark')|
If you have a field DATE or DATETIME in your table then this solution maybe can help you.
Let say your table name my_table and has PK id (INT) and also a field bila (DATE). I just need to get last (biggest) id in current month from my_table then add by 1.
SET #mos= (SELECT MAX(id) FROM my_table WHERE MONTH(`bila`) = MONTH(NOW()) AND YEAR(`bila`) = YEAR(NOW()));
SET #mos = IF(
#mos IS NULL,
CONCAT(YEAR(NOW()),MONTH(NOW()),'001'),
#mos + 1
);
Then u can use #mos in your query next
To reset the AUTO_INCREMENT value, drop and recreate the table1_seq table. Given your example, a TRUNCATE statement would be sufficient (given that there aren't any foreign keys, and we assume the table is using either the MyISAM or InnoDB engine).
TRUNCATE TABLE table1_seq ;
(MySQL behavior for this statement is to create a new, empty table, with the AUTO_INCREMENT set back to the value when the table was created.)
This effectively achieves the same result as a DROP table followed by CREATE table.
That answers the question you asked. As a side note, generating a key value this way usually turns out to be a bad idea.
i've relied on the last answer above, i've used the orderDate field from my table and compared it with the current date during insertion , to decide finally if i want to reset or increment the purchaseOrderRef field:
The aim is to insert custom auto increment order id (field name: "purchaseOrderRef" ) with the format DD-MM-XXX in table [Products_SumOrders]. such that it resets the XXX to 0 automatically every month:
USE [Mydatabase] -- here you need to use your own database
GO
/****** Object: Trigger [dbo].[customAutoIncrement] Script Date: 10/1/2016 10:07:41 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[customAutoIncrement]
ON [dbo].[Products_SumOrders]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
declare #maxOrderID int;
declare #maxOrderRef nvarchar(max);
declare #relativeID varchar(max);
declare #orderId int;
select #orderId =orderid from inserted;
print(#orderId);--allow me to display the inserted order id
SET #maxOrderID = (SELECT Max(orderid) FROM [Products_SumOrders] WHERE MONTH([OrderDate]) = (MONTH(GETDATE())) AND YEAR([OrderDate]) = YEAR(GETDATE()) and orderid < #orderId );
print(#maxOrderID);--last added order
--custom month format (always MM):
declare #mon int;
declare #stringMon nvarchar(10);
set #mon= MONTH(GETDATE());
IF #mon <10
set #stringMon ='0' + CONVERT(VARCHAR(1),#mon) ;
ELSE
set #stringMon = CONVERT(VARCHAR(2),#mon) ;
IF #maxOrderID is null --no orders has been added in this month:
begin
set #maxOrderRef = Substring(CONVERT(VARCHAR(4),YEAR(GETDATE())),3,4)+ '-'+ CONVERT(VARCHAR(2),#stringMon)+'-001';
end
ELSE
--custom order id format (always XXX):
begin
set #relativeID =(SELECT [purchaseOrderRef] FROM [Products_SumOrders] WHERE orderid=#maxOrderID);
set #relativeID = Substring(#relativeID,LEN(#relativeID)-(Charindex('-', REVERSE(#relativeID))-2),LEN(#relativeID));
print(CONVERT(int,#relativeID));
IF CONVERT(int,#relativeID) < 9
set #relativeID ='00' + CONVERT(VARCHAR(2),#relativeID+1) ;
ELSE
begin
if CONVERT(int,#relativeID) < 99
set #relativeID ='0' + CONVERT(VARCHAR(3),#relativeID+1) ;
else
set #relativeID = CONVERT(VARCHAR(3),#relativeID+1) ;
end
set #maxOrderRef = Substring(CONVERT(VARCHAR(4),YEAR(GETDATE())),3,4)+ '-'+ CONVERT(VARCHAR(2),#stringMon)+'-'+ CONVERT(VARCHAR(3),#relativeID);
end
print(#maxOrderRef);
UPDATE Products_SumOrders
SET purchaseOrderRef = #maxOrderRef
FROM inserted INNER JOIN [Products_SumOrders] On inserted.orderid = [Products_SumOrders].orderid
END
GO

SSRS String -vs- Data Integer

I am working on a SSRS report and using a parameter that allows you to choose multiple options. However, when I do this I get an error that states:
Error Converting Data Type nVarChar to Int.
The data in the database is an Integer. The parameter is set up as an Integer and it works great when only choosing one option. The issue comes when I choose multiple options.
My co-worker came up with one work-around but I would like something a little more elegant and easier to plug in if possible.
Here is his work-around:
ALTER PROCEDURE [dbo].[DtaPrep_MktgClients]
#BegDate date = NULL
, #EndDate date = NULL
, #Species varchar(50) = 'canine,feline,K9,'
 , #HospList varchar(500) = NULL
This is where the hospmastid string gets converted into a temp table
/*
--===================================--
HOSPITALS SETUP
--===================================--
*/
If #HospList IS NOT NULL
BEGIN
DECLARE #WorkHospList varchar(500)
SET #WorkHospList = #HospList
;
CREATE TABLE #HospList
( HospID smallint NULL )
SET #CommaLoc = charindex(',', #WorkHospList)
WHILE #CommaLoc > 1
BEGIN
SET #curVal = LEFT(#WorkHospList, #commaloc-1 )
INSERT INTO
#HospList( HospID )
SELECT #curVal
SET #WorkHospList = substring( #WorkHospList, #commaloc+1, len(#WorkHospList) )
SET #CommaLoc = charindex(',', #WorkHospList)
END
END
This is using the temp table to accomplish the same thing as a “WHERE Hospmastid IN (101,102,103)…”
Method 1
SELECT
HospitalMasterID
, ClientID
, FirstName
, LastName
FROM
Client
WHERE
HospitalMasterID IN (Select HospID From #HospList )
Needless to say, I am sure there is a better way to accomplish this. If anyone has any ideas, please let me know.
Here is the full Query I am now using. But it is not selecting anything so there is an issue with the Created Table.
USE [xxxxx]
GO
/****** Object: StoredProcedure [dbo].[PriceErosion] Script Date: 11/26/2013 8:26:33 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
-- =============================================
-- Author:
-- Create date: 11/25/2013
-- Description: Determines the products in which the price was lowered and revenue lost during a set time period.
-- =============================================
*/
--#StartDate as Date = Null
--,#EndDate as Date = Null
--,#CurDate as Date = Null
--,#Hospital as VarChar = Null
--,#Division as Int = Null
Declare #StartDate as Date = Null
Declare #EndDate as Date = Null
Declare #Hospital as Int = Null
Declare #Division as Int = Null
DECLARE #curDate Date = Null
SET #curDate = GETDATE()
Set #StartDate = CASE WHEN #StartDate IS NULL THEN DATEADD(dd, -31, Dateadd(dd, -1, #curdate) ) ELSE #StartDate END
Set #EndDate = CASE WHEN #EndDate IS NULL THEN Dateadd(dd, -1, #curdate) ELSE #EndDate END
Set #Hospital = Case When #Hospital IS Null Then '3' Else #Hospital End;
IF OBJECT_ID('tempdb.dbo.#HospList') IS NOT NULL DROP TABLE #HospList ;
If #Hospital IS NOT NULL
BEGIN
DECLARE #WorkHospList varchar(500)
Declare #CommaLoc as Int
Declare #curVal as int
SET #WorkHospList = #Hospital
;
CREATE TABLE #HospList
( HospID smallint NULL )
SET #CommaLoc = charindex(',', #WorkHospList)
WHILE #CommaLoc > 1
BEGIN
SET #curVal = LEFT(#WorkHospList, #commaloc-1 )
INSERT INTO
#HospList( HospID )
SELECT #curVal
SET #WorkHospList = substring( #WorkHospList, #commaloc+1, len(#WorkHospList) )
SET #CommaLoc = charindex(',', #WorkHospList)
END
END
Begin
-- Sets the Baseline Price Date in the PriceChangeHistory Table.
With PC1
as
(Select
HospitalMasterID
,TxnCode
,UserInfoMasterID
,Active
,min(TxnDateTime) as StartingDate
From
PriceChangeHistory
Where
TxnDateTime Between #StartDate and #EndDate
Group By
HospitalMasterID, TxnCode, UserInfoMasterID, Active)
-- Gets the Baseline Price for the period from the PriceChangeHistory Table
,PC
as
(Select
PC1.HospitalMasterID
,PC1.TxnCode
,PC1.UserInfoMasterID
,PC1.Active
,Cast (PC1.StartingDate as Date) as StartingDate
,PC2.OldPrice as StartingPrice
,PC2.NewPrice
,PC2.TxnSubType
From
PC1
Inner Join
PriceChangeHistory as PC2
On
PC1.HospitalMasterID = PC2.HospitalMasterID
and
PC1.TxnCode = PC2.TxnCode
and
PC1.StartingDate = PC2.TxnDateTime
Where
PC2.OldPrice > PC2.NewPrice)
--MedicalHistory Information
,MH
as
(Select
HospitalMasterID
,PatientID
,TxnDate
,TxnCode
,Description
,ListAmount
,ExtendedAmount
,TxnType
,Quantity
,(Case
When Quantity <> '1' Then (ListAmount/Quantity)
Else ListAmount
End) as UnitPrice
From
MedicalHistory
Where
TxnDate Between #StartDate and #EndDate
and
_IsServOrITem = 1)
-- Determines the Revenue lost per each sale, also reduces the results to only those items where the Price was lowered not raised.
,RL
as
(Select
PC.HospitalMasterID
,MH.PatientID
,PC.TxnCode
,PC.TxnSubType
,MH.Description
,PC.UserInfoMasterID as ChangedByUserID
,MH.TxnDate
,PC.StartingPrice
,Cast (MH.UnitPrice as Money) as UnitPrice
,Cast ((StartingPrice - UnitPrice) as Money) as RevenueLost
From
PC
Left OUter Join
MH
on
PC.HospitalMasterID = MH.HospitalMasterID
and
PC.TxnCode = MH.TxnCode
Where
PC.StartingPrice > MH.UnitPrice)
--- Determine the name of the tech changing the prices.
,UI
as
(Select
HospitalMasterID
,UserInfoMasterID
,Name
From
UserInfo)
--- Get the Division and Hospital Name for each Hospital.
,HODI
as
(Select
DI.DivisionID
,DI.DivisionName
,HO.HospMastID
,HO.HospCode
,HO.HospName
From
ref_Hospital as HO
inner Join
ref_Division as DI
on
HO.DivisionID = DI.DivisionID)
,HI
as
(Select
HODI.DivisionID
,HODI.DivisionName
,RL.HospitalMasterID
,HODI.HospCode
,HODI.HospName
,RL.PatientID
,RL.TxnCode
,RL.TxnSubType
,RL.Description
,RL.ChangedByUserID
,RL.TxnDate
,RL.StartingPrice
,RL.UnitPrice
,RL.RevenueLost
From
RL
Left Outer Join
HODI
ON
RL.HospitalMasterID = HODI.HospMastID
Where
TXNDate Between #StartDate and #EndDate)
Select
*
From
HI
Where
HospitalMasterID in (Select HospID from #Hosplist)
Order By
HOspitalMasterID
end
Prior to SQL Server 2008, the standard way to filter by one or more values was to pass an XML document to the Stored Procedure and join on it. In this case, you could pass the data as a string with the integers separated by commas, then convert that into an XML document, then join on the XML. So you should change the multiselect in SSRS to a text datatype. Here's a post that shows you how to open an XML document: http://blog.sqlauthority.com/2009/02/13/sql-server-simple-example-of-reading-xml-file-using-t-sql/
SQL Server 2008 lets you use table-valued parameters, but again, it might be best to pass the data as a string of comma separated integers and then let the stored procedure put the data into a table-valued parameter, and then join on that. Here's a post that describes how to use table valued parameters: http://blog.sqlauthority.com/2008/08/31/sql-server-table-valued-parameters-in-sql-server-2008/

Select in MySQL stored procedure not returning values

I have a stored procedure, shown below, which I created to add dollar sales to a table (WeeklySales) which currently stores only unit sales. The cursor operates on on the WeeklySales table. The pricing data is stored in the Pricing table. The Pricing table actually contains changes in prices. The effective date for a price change is stored in Pricing.effectiveDate, so I have to find the pricing which was effective for the week in which the unit was sold (which is stored in WeeklySales.weekStart).
The problem I'm having is that the first select after the IF doesn't return anything. I've confirmed that this select does return a value when I run it outside of the procedure using the values which it would be called with inside the procedure. I'm not sure what's wrong here, but I'm guessing maybe this has to do with the fact that the this select is operating on a table which is different from the cursor? Anyone know? Is there a better way to do this?
DELIMITER //
CREATE PROCEDURE `createWeeklyPricing` (IN startDate DATE, IN endDate DATE)
BEGIN
--
-- Populate the proceeds column using the Pricing table
DECLARE product VARCHAR(255);
DECLARE weekStart DATE;
DECLARE units, done INT;
DECLARE proceeds DECIMAL(6,2);
DECLARE effectiveDate DATE;
DECLARE currentRow CURSOR FOR SELECT `weekStart`, `product`, `units` FROM `WeeklySales` WHERE `weekStart` >= startDate AND `weekStart` <= endDate;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN currentRow;
SET done = 0;
WHILE done = 0 DO
FETCH currentRow INTO weekStart, product, units;
IF done = 0 THEN
SELECT MAX(`effectiveDate`) FROM `Pricing` WHERE `effectiveDate` <= weekStart AND `product` = product INTO effectiveDate;
SELECT `proceeds` FROM `Pricing` WHERE `effectiveDate` = effectiveDate AND `product` = product INTO proceeds;
UPDATE `WeeklySales` SET `proceeds` = units * proceeds WHERE `weekStart` = weekStart AND `product` = product;
END IF;
END WHILE;
CLOSE currentRow;
END//
echo (select) weekstart before the if statement...
If it returns null change the select FROM WeeklySales WHERE weekStart between startDate AND endDate
you need to use the INTO before FROM and variable needs '#' sign
change it to
SELECT MAX(`effectiveDate`) INTO #effectiveDate FROM `Pricing` WHERE `effectiveDate` <= weekStart AND `product` = product ;
hope this helps
This is because your variable name is overwriting your column name:
You have a variable named 'effectiveDate'
You have a column named 'effectiveDate'
SELECT MAX(`effectiveDate`) ...
Is MAX-ing the variable effectiveDate, not the column
Try naming the variable maxEffectiveDate
Beware that variables are case insensitive. This happened to me when i tried to select column IsBackUp into variable isBackUp (notice the i).