Auto Increment mysql trigger - mysql

How create a Auto increment field based on this example:
I have this table, with "AF" field, in that format: SN.MM.YYYY
The "SN" = AI number based on last insert, MM= Atual Month, YYYY = Atual Year.
| ID | AF |
____________________
| 1 | 01.10.2013 |
| 2 | 02.10.2013 |
So, when changes the month or year, the trigger must set "AF" field that way:
Ex.: Month changes to November(Reset SN to 01).
| 3 | 01.11.2013 |
| 4 | 02.11.2013 |
The same thing when year changes(Reset SN to 01):
| 5 | 01.01.2014 |
| 6 | 02.01.2014 |
| 7 | 03.01.2014 |
Anyone know's how set that trigger?
Obs: There may be more than one record in one day, so, day is not important.
Sorry for the bad english
Thanks guys!

Technically you can do something like this
CREATE TRIGGER tg_bi_table1
BEFORE INSERT ON table1
FOR EACH ROW
SET NEW.af = CONCAT(
LPAD(COALESCE(
(SELECT MAX(LEFT(af, 2))
FROM table1
WHERE af LIKE DATE_FORMAT(CURDATE(), '__.%m.%Y')), 0) + 1, 2, '0'),
DATE_FORMAT(CURDATE(), '.%m.%Y'));
Here is SQLFiddle demo
Note: This approach (creating your own ago_increment values with such a pattern) has two major drawbacks:
Under heavy concurrent access different connections may obtain the same AF number
Because of your particular AF pattern (SN comes first) using an index is impossible therefore you'll end up always getting a full scan

Related

Need an aggregate MySQL select that iterates virtually across date ranges and returns bills

I have a MySQL table named rbsess with columns RBSessID (key), ClientID (int), RBUnitID (int), RentAmt (fixed-point int), RBSessStart (DateTime), and PrevID (int, references to RBSessID).
It's not transactional or linked. What it does track when a client was moved into a room and what the rent at the time of move in was. The query to find what the rent was for a particular client on a particular date is:
SET #DT='Desired date/time'
SET #ClientID=Desired client id
SELECT a.RBSessID
, a.ClientID
, a.RBUnitID
, a.RentAmt
, a.RBSessStart
, b.RBSessStart AS RBSessEnd
, a.PrevID
FROM rbsess a
LEFT
JOIN rbsess b
ON b.PrevID=a.RBSessID
WHERE a.ClientID=#ClientID
AND (a.RBSessStart<=#DT OR a.RBSessStart IS NULL)
AND (b.RBSessStart>#DT OR b.RBSessStart IS NULL);
This will output something like:
+----------+----------+----------+---------+---------------------+-----------+--------+
| RBSessID | ClientID | RBUnitID | RentAmt | RBSessStart | RBSessEnd | PrevID |
+----------+----------+----------+---------+---------------------+-----------+--------+
| 2 | 4 | 1 | 57500 | 2020-11-22 00:00:00 | NULL | 1 |
+----------+----------+----------+---------+---------------------+-----------+--------+
I also have
SELECT * FROM rbsess WHERE rbsess.ClientID=#ClientID AND rbsess.PrevID IS NULL; //for finding the first move in date
SELECT TIMESTAMPDIFF(DAY,#DT,LAST_DAY(#DT)) AS CountDays; //for finding the number of days until the end of the month
SELECT DAY(LAST_DAY(#DT)) AS MaxDays; //for finding the number of days in the month
SELECT (TIMESTAMPDIFF(DAY,#DT,LAST_DAY(#DT))+1)/DAY(LAST_DAY(#DT)) AS ProRateRatio; //for finding the ratio to calculate the pro-rated rent for the move-in month
SELECT ROUND(40000*(SELECT (TIMESTAMPDIFF(DAY,#DT,LAST_DAY(#DT))+1)/DAY(LAST_DAY(#DT)) AS ProRateRatio)) AS ProRatedRent; //for finding a pro-rated rent amount based on a rent amount.
I'm having trouble putting all of these together to form a single query that can output pro-rated and full rent amounts based on a start date and an optional end date all rent owed amounts in a single statement for each month in the period. I can add a payments table received and integrate it afterwards, just having a hard time with this seemingly simple real-world concept in a MySQL query. I'm using php with a MySQL back end. Temporary tables as intermediary queries are more than acceptable.
Even a nudge would be helpful. I'm not super-experienced with MySQL queries, just your basic CREATE, SELECT, INSERT, DROP, and UPDATE.
Examples as requested by GMB:
//Example data in rbsess table:
+----------+----------+----------+---------+---------------------+--------+
| RBSessID | ClientID | RBUnitID | RentAmt | RBSessStart | PrevID |
+----------+----------+----------+---------+---------------------+--------+
| 1 | 4 | 1 | 40000 | 2020-10-22 00:00:00 | NULL |
| 2 | 4 | 1 | 57500 | 2020-11-22 00:00:00 | 1 |
| 3 | 2 | 5 | 40000 | 2020-11-29 00:00:00 | NULL |
+----------+----------+----------+---------+---------------------+--------+
Expected results would be a list of the rent amounts owed for every month, including pro-rated amounts for partial occupancy in a month, from a date range of months. For example for the example data above for a date range spanning all of the year of 2020 from client with ClientID=4 the query would produce an amount for each month within the range similar to:
Month | Amt
2020-10-1 | 12903
2020-11-1 | 45834
2020-12-1 | 57500

Issue with Group by Mysql query

I have been stumped by this MySQL query for the past few day,and seeking some expert help before i throw my PC out of the window, lol.
I have a table that consists of invoices; invoice number column name is Trans_ref$$ (primary key).
each invoice is linked to a job , column name is OPSREF$$_ORIGINAL (foreign key).
Both columns are in the same table.
a job can have multiple invoices.
Now the issue is i'm trying to create a query that will identify the FIRST invoice in sequence (Trans_ref$$) in a job group and if that FIRST invoice is with a date range then output the job (OPSREF$$_ORIGINAL).
The invoice number is sequential and a unique number.
I have tried using a case / min group by statement to identify the first invoice in a job group within a data range, however this query is not isolating the first invoice within a date range, instead it is just outputting 1st or 2nd or 3rd positioned invoice in job group that matches the date range….I hope this makes sense .
I have included a screen shot of the table and the desired output, and would appreciate if someone
Hello
I have been stumped by this query for the past day,and seeking some expert help before i throw my PC out of the window, lol.
I have a table that consists of invoices; invoice number column name is Trans_ref$$ (primary key).
each invoice is linked to a job , column name is OPSREF$$_ORIGINAL (foreign key).
Both columns are in the same table.
a job can have multiple invoice.
Now the issue is i'm trying to create a query that will identify the FIRST invoice (Trans_ref$$) in a job group and if that FIRST invoice is with a date range then output the job (OPSREF$$_ORIGINAL).
The invoice number in a sequential / unique number.
I have tried using a case / min group by statement to identify the first invoice in a job group within a data range, however this query is not isolating the first invoice within a date range, instead it is just outputting 1st or 2nd or 3rd positioned invoice in job group that matches the date range….I hope this makes sense .
Here the code I have used
SET #START_DATE := "2014-08-27";
SET #END_DATE:= "2014-09-02";
select
count(TRANS_REF$$),
Case
when min(TRANS_REF$$) and INVOICE_DATE_D8>=#START_DATE and INVOICE_DATE_D8<=#END_DATE
then OPSREF$$_ORIGINAL
end as OPSREF$$_ORIGINAL
from INVOICE_HEADER_UNS
where
TRANSACTION_STATUS = 9
and Tmode$$="06"
group by OPSREF$$_ORIGINAL
So to breakdown the process in stages.....
1. grab each OPSREF$$_ORIGINAL group within the INVOICE_HEADER_UNS table
Date Range - Start 27/08/2014 - End 02/09/2014
TABLE - INVOICE_HEADER_UNS
TRANS_REF$$ INVOICE_DATE_D8 OPSREF$$_ORIGINAL
---------------------------------------------
| 1 | 26/08/2014 | ABC |
| 2 | 02/08/2014 | ABC |
---------------------------------------------
| 3 | 28/08/2014 | DDD |
| 4 | 09/09/2014 | DDD |
---------------------------------------------
| 5 | 01/01/2013 | JJJ |
| 6 | 21/12/2013 | JJJ |
---------------------------------------------
| 7 | 01/09/2014 | LLL |
---------------------------------------------
2. within each OPSREF$$_ORIGINAL group, look at TRANS_REF$$ sequence and find the first TRANS_REF$$ in that OPSREF$$_ORIGINAL group.
Date Range - Start 27/08/2014 - End 02/09/2014
TABLE - INVOICE_HEADER_UNS
TRANS_REF$$ INVOICE_DATE_D8 OPSREF$$_ORIGINAL Is First inv?
--------------------------------------------------------
| 1 | 26/08/2014 | ABC | yes
| 2 | 02/08/2014 | ABC | no
--------------------------------------------------------
| 3 | 28/08/2014 | DDD | yes
| 4 | 09/09/2014 | DDD | no
---------------------------------------------------------
| 5 | 01/01/2013 | JJJ | yes
| 6 | 21/12/2013 | JJJ | no
---------------------------------------------------------
| 7 | 01/09/2014 | LLL | yes
---------------------------------------------------------
3. Look at the the FIRST INVOICE in the ordered sequence for the group and check the INVOICE_DATE_D8 for that row and see if it is within date range ( 27/08/2014 - 02/09/2014 )
Date Range - Start 27/08/2014 - End 02/09/2014
TABLE - INVOICE_HEADER_UNS
TRANS_REF$$ INVOICE_DATE_D8 OPSREF$$_ORIGINAL Is First inv? In date range?
--------------------------------------------------------
| 1 | 26/08/2014 | ABC | yes no
--------------------------------------------------------
| 3 | 28/08/2014 | DDD | yes yes
---------------------------------------------------------
| 5 | 01/01/2013 | JJJ | yes no
---------------------------------------------------------
| 7 | 01/09/2014 | LLL | yes yes
4. Does each row meet the criteria (i.e. first invoice and in date - YES + YES) ? if correct then output the distinct OPSREF$$_ORIGINAL for that row
Here is the desired output from the example above
Date Range - Start 27/08/2014 - End 02/09/2014
TABLE - INVOICE_HEADER_UNS
OPSREF$$_ORIGINAL Is First inv? In date range?
------------------------
| DDD | yes yes
------------------------
| LLL | yes yes
------------------------
Based on this, can you suggest how I can do this? thanks
Here is the Table definition;
tablename - INVOICE_HEADER_UNS
**TRANS_REF$$** char(7) - Primary key
INVOICE_DATE_D8 datatime
OPSREF$$_ORIGINAL char(11)
16/09/2014 - Here is the query that appears to be returning the correct results using DRapp syntax, however the query needs to be optimised somehow as when I bolt this onto the bigger query as a sub query it causes my MYSQL workbench to crash. After doing an explain on the query , it appears to be indexing through 28,309 rows. How can i optimise this query without impacting the results?
I have tried adding the below to the where clause however it adds more records to the overall query output, but indexes 979 rows instead/
set #START_DATE := '2014-08-27';
set #END_DATE := '2014-09-02';
SELECT
if (min(ihu.INVOICE_DATE_D8)>= #START_DATE and min(ihu.INVOICE_DATE_D8)<= #END_DATE ihu.opsref$$_original, null) as firstinvoiceindaterange
from
INVOICE_HEADER_UNS ihu
join CONSIGNMENT_ALL_HEADER_UNS on ihu.OUR_REF = CONSIGNMENT_ALL_HEADER_UNS.OPSREF$$
where ihu.TRANSACTION_STATUS = 9 and ihu.Tmode$$="06"
AND CONSIGNMENT_ALL_HEADER_UNS.CONS_TYPE$$ <>'7'
AND CONSIGNMENT_ALL_HEADER_UNS.CONS_TYPE$$ in ('3' , '5', '9')
#and ihu.INVOICE_DATE_D8>= #START_DATE and ihu.INVOICE_DATE_D8<= #END_DATE
group by
ihu.opsref$$_original
I think this should help you out, and you can tweak it as needed.
SELECT
ihu.opsref$$_original,
MIN( ihu.TRANS_REF$$ ) MinRefForEntireJob,
MIN( ihu.INVOICE_DATE_D8 ) MinDateForEntireJob,
MIN( IF( ihu.INVOICE_DATE_D8 >= #START_DATE
AND ihu.INVOICE_DATE_D8 <= #END_DATE, ihu.TRANS_REF$$, null )) as MinRefWithinDateRange,
MIN( IF( ihu.INVOICE_DATE_D8 >= #START_DATE
AND ihu.INVOICE_DATE_D8 <= #END_DATE, ihu.INVOICE_DATE_D8, null )) as MinDateWithinDateRange
from
INVOICE_HEADER_UNS ihu,
( select #START_DATE := '2014-08-27',
#END_DATE := '2014-09-02' ) sqlvars
group by
ihu.opsref$$_original
Once you see these results, then you SHOULD be able to just add a HAVING clause something like
HAVING
MinDateWithinDateRange IS NOT NULL

Access a parent field from sub query in mysql

I'm trying to access a field being called from the parent query within a nested one and here is my table
TABLE: reminders.
Columns: id:PK, rid:VARCHAR, title:VARCHAR, remind:Integer, start_day:DATE
SELECT id, remind, rid, title
FROM reminders
WHERE DATEDIFF(start_day, NOW()) <= (SELECT LEAST(3, remind))
Basically the second "remind" column in the LEAST() command is suppossed to reference the first "remind" column value for every row being spanned but for reasons that I can't just imagine i keep getting unexpected returns.
EDIT
In response to Sir Gordons that i provide more detailed info, I will try my best but I really do not know how to present table data here, but i'll try.
So basically i'm trying to SELECT all items from the reminders table WHERE the DIFFERENCE between the SET DAY (start_day) and TODAY doesn't exceed one of TWO values, those are either 3 or the value set in the remind column of the current row. Basically if the value set there is less than 3 then it should be used instead, but if it exceeds 3, 3 should be chosen. Here's a visual of the table.
+---+-----------------+--------------------+-----------------+-------------+
|id | rid | title | start_day | remind |
+---|-----------------|--------------------|-----------------|-------------|
|1 | ER456GH | This is real deep | 2014-01-01 | 10 |
|2 | OUBYV90 | This is also deep | 2014-01-13 | 10 |
|3 | UI90POL | This is deeper | 2014-01-13 | 60 |
|4 | TWEET90 | This is just deep | 2014-01-14 | 0 |
+---+-----------------+--------------------+-----------------+-------------+
So in editing this I realized that there was a false table entry under remind on the 4th entry that was causing it to pull false (i.e where remind = 0). Sigh. Some serious short sight on my part/lack of sleep I guess. The query does work . Thanks again.
You don't need a subquery here. Does this work?
SELECT id, remind, rid, title
FROM reminders
WHERE DATEDIFF(start_day, NOW()) <= LEAST(3, remind);

MySQL - subtracting row 2 from row 1 where column is the same

I am creating a temp table which currently pulls values in for today and yesterday. The temp table looks like this:
|DateTime |company 1 |company 2 |
+------------------------+----------------------+
|2013-10-03 14:40:00 | 182475 | 110271 |
|2013-10-02 14:10:00 | 182086 | 110261 |
What I need to do is select the values from today, as well as the difference between today and yesterday. Based on the above data, the output would look like this:
Company 1 | Company 1 difference | Company 2| Company 2 difference
+-----------+----------------------+----------+--------------------------
182475 | 389 | 110271 | 10
I can't figure out how to specify which row to subtract from which, since there is no auto-increment field and the DateTime field will be slightly different each day.
Thanks for the help!
SELECT today.DateTime as DateTime
, today.Company1, today.Company1 - COALESCE(yesterday.Company1,0) AS Company1Diff
, today.Company2, today.Company2 - COALESCE(yesterday.Company2,0) AS Company2Diff
FROM tbl AS today
LEFT JOIN tbl AS yesterday
ON DATEDIFF(today.DateTime, yesterday.DateTime) = 1
ORDER BY today.DateTime ASC

MySQL - COUNT before INSERT in one query

Hey all, I am looking for a way to query my database table only once in order to add an item and also to check what last item count was so that i can use the next number.
strSQL = "SELECT * FROM productr"
After that code above, i add a few product values to a record like so:
ID | Product | Price | Description | Qty | DateSold | gcCode
--------------------------------------------------------------------------
5 | The Name 1 | 5.22 | Description 1 | 2 | 09/15/10 | na
6 | The Name 2 | 15.55 | Description 2 | 1 | 09/15/10 | 05648755
7 | The Name 3 | 1.10 | Description 3 | 1 | 09/15/10 | na
8 | The Name 4 | 0.24 | Description 4 | 21 | 09/15/10 | 658140
i need to count how many times it sees gcCode <> 'na' so that i can add a 1 so it will be unique. Currently i do not know how to do this without opening another database inside this one and doing something like this:
strSQL2 = "SELECT COUNT(gcCode) as gcCount FROM productr WHERE gcCode <> 'na'
But like i said above, i do not want to have to open another database query just to get a count.
Any help would be great! Thanks! :o)
There's no need to do everything in one query. If you're using InnoDB as a storage engine, you could wrap your COUNT query and your INSERT command in a single transaction to guarantee atomicity.
In addition, you should probably use NULL instead of na for fields with unknown or missing values.
They're two queries; one is a subset of the other which means getting what you want in a single query will be a hack I don't recommend:
SELECT p.*,
(SELECT COUNT(*)
FROM PRODUCTR
WHERE gccode != 'na') AS gcCount
FROM PRODUCTR p
This will return all the rows, as it did previously. But it will include an additional column, repeating the gcCount value for every row returned. It works, but it's redundant data...