I have a MySQL table where I display debit, credit and balance in my table. I have loaded the following definition, sample data and code into SQL Fiddle:
CREATE TABLE chequebook (
entry_date timestamp default now() PRIMARY KEY,
entry_item varchar(48) NOT NULL DEFAULT '',
entry_amount decimal(10,2) NOT NULL DEFAULT 0.00
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO chequebook (entry_date,entry_item,entry_amount) VALUES
('2010-01-02 12:34:00','Deposit A',215.56),
('2010-01-02 21:44:00','Withdrawal A' ,-23.34),
('2010-01-03 10:44:00','Withdrawal B',-150.15),
('2010-01-03 15:44:00','Deposit B',154.67),
('2010-01-04 18:44:00','Withdrawal C',-65.09),
('2010-01-05 08:44:00','Withdrawal D',-74.23),
('2010-01-06 14:44:00','Deposit C',325.12),
('2010-01-06 20:44:00','Withdrawal E',-80.12),
('2010-01-07 04:44:00','Withdrawal F',-110.34),
('2010-01-07 16:44:00','Withdrawal G',-150.25),
('2010-01-08 16:44:00','Withdrawal H',-23.90),
('2010-01-08 21:44:00','Withdrawal I',-75.66),
('2010-01-08 22:44:00','Deposit C',275.78),
('2010-01-09 11:44:00','Withdrawal K',-85.99),
('2010-01-09 21:44:00','Withdrawal J',-100.00);
set #depos=0;
set #total=0;
select
entry_date,
entry_item,
entry_amount,
if( entry_amount>0, #depos:=entry_amount, #depos:=#depos+entry_amount ) as depos_bal,
#total:=#total+entry_amount as net_bal
from chequebook
order by entry_date;
I am facing issues when I want to add an opening balance to the net_bal column from the PHP MYSQL query.
I am facing issues in adding the Opening Balance to the very FIRST COLUMN and there after it should minus or plus from the desired fields.
For example:
| entry_date | entry_item | entry_amount | depos_bal | net_bal |
|---------------------------|--------------|--------------|-----------|---------|
| January, 02 2010 12:34:00 | Deposit A | 215.56 | 5215.56 | 5215.56 | <--- 5000 is openingbalance
| January, 02 2010 21:44:00 | Withdrawal A | -23.34 | 5192.22 | 5192.22 |
| January, 03 2010 10:44:00 | Withdrawal B | -150.15 | 5042.07 | 5042.07 |
Opening Balance is fetched from different table.
How can I finish this?
You can set the initial local #Total variable to your initial balance. From your SQLFiddle:
set #depos=0;
set #total=5000;
select
entry_date,
entry_item,
entry_amount,
if( entry_amount>0, #depos:=entry_amount, #depos:=#depos+entry_amount ) as depos_bal,
#total:=#total+entry_amount as net_bal from chequebook
order by entry_date;
If it's coming from a different query, set the variable that way.
Related
I am trying to select offers between two dates, one of start and one of expiration and in case the expiration date is empty or null it will always show the offers.
Table
+----------------+---------------------+---------------------+
| deal_title | deal_start | deal_expire |
+----------------+---------------------+---------------------+
| Example Deal | 10-24-2021 16:10:00 | 10-25-2021 16:10:00 |
| Example Deal 2 | 10-24-2021 16:10:00 | NULL |
+----------------+---------------------+---------------------+
Php Function to get the current date by timezone.
function getDateByTimeZone(){
$date = new DateTime("now", new DateTimeZone("Europe/London") );
return $date->format('m-d-Y H:i:s');
}
Mysql query:
SELECT deals.*, categories.category_title AS category_title
FROM deals
LEFT JOIN categories ON deal_category = categories.category_id
WHERE deals.deal_status = 1
AND deals.deal_featured = 1
AND deals.deal_start >= '".getDateByTimeZone()."'
AND '".getDateByTimeZone()."' < deals.deal_expire
OR deals.deal_expire IS NULL
OR deals.deal_expire = ''
GROUP BY deals.deal_id ORDER BY deals.deal_created DESC
You didn't really explain what problem you're having. Having written queries like this many times in the past, you likely need parentheses around the expiration side of your date qualifications.
WHERE deals.deal_status = 1
AND deals.deal_featured = 1
AND deals.deal_start >= '".getDateByTimeZone()."'
AND (
'".getDateByTimeZone()."' < deals.deal_expire
OR deals.deal_expire IS NULL
)
If you don't put parentheses around your OR clause, then operator precedence will cause the whole WHERE clause to be true whenever the expire date is NULL and that's not what you want. You want a compounded OR clause here.
I don't think you need to compare against empty string either, just assuming you put that in there trying to figure things out so I left it out in my sample code.
Also I'm not familiar with PHP string interpolation enough to know if there's an issue with the way you're interpolating the result of the 'getDateByTimeZone' function into that query. It looks funky to me based on past experience with PHP, but I'm ignoring that part of it under the assumption that there's something wrapping this code which resolves it correctly.
The best would be to have MySQL datetimes from the start in your database
But you can do all in MySQL.
STR_TO_DATE will cost time every time it runs
When you put around all expire dates a () it will give back a true if youe of them is true
CREATE TABLE deals (
deal_id int,
deal_status int,
deal_featured int,
deal_category int,
`deal_title` VARCHAR(14),
`deal_start` VARCHAR(19),
`deal_expire` VARCHAR(19)
,deal_created DATEtime
);
INSERT INTO deals
(deal_id,deal_status,deal_featured,deal_category,`deal_title`, `deal_start`, `deal_expire`,deal_created)
VALUES
(1,1,1,1,'Example Deal', '10-24-2021 16:10:00', '10-25-2021 16:10:00',NOW()),
(2,1,1,1,'Example Deal 2', '10-24-2021 16:10:00', NULL,NOW());
CREATE TABLE categories (category_id int,category_title varchar(20) )
INSERT INTO categories VALUES(1,'test')
SELECT
deals.deal_id, MIN(`deal_title`), MIN(`deal_start`), MIN(`deal_expire`),MIN(deals.deal_created) as deal_created , MIN(categories.category_title)
FROM
deals
LEFT JOIN
categories ON deal_category = categories.category_id
WHERE
deals.deal_status = 1
AND deals.deal_featured = 1
AND STR_TO_DATE(deals.deal_start, "%m-%d-%Y %H:%i:%s") >= NOW() - INTERVAL 1 DAY
AND (NOW() < STR_TO_DATE(deals.deal_expire, "%m-%d-%Y %H:%i:%s")
OR deals.deal_expire IS NULL
OR deals.deal_expire = '')
GROUP BY deals.deal_id
ORDER BY deal_created DESC
deal_id | MIN(`deal_title`) | MIN(`deal_start`) | MIN(`deal_expire`) | deal_created | MIN(categories.category_title)
------: | :---------------- | :------------------ | :------------------ | :------------------ | :-----------------------------
1 | Example Deal | 10-24-2021 16:10:00 | 10-25-2021 16:10:00 | 2021-10-24 22:42:34 | test
2 | Example Deal 2 | 10-24-2021 16:10:00 | null | 2021-10-24 22:42:34 | test
db<>fiddle here
I have a database table with holiday requests in it. I now want to calculate, how many days the user has requested for a certain year. So far I did this:
Table:
CREATE TABLE `holidays` (
`id` int(11) NOT NULL,
`user` int(11) NOT NULL,
`begin` date NOT NULL,
`end` date NOT NULL,
`comment_user` text NOT NULL,
`entered_at` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Get all holidays in a year:
SELECT SUM((DATEDIFF(end, begin) + 1)) AS days
FROM holidays
WHERE user = :user AND begin LIKE '2021%'
But what can I do, if begin date is in the year before (e.g. 12/30/2020) or end date is in the next year (e.g. 01/05/2022), so the request extends over new year's eve.
EXAMPLE:
If I have a holiday request from 12/30/2020 to 01/02/2021, I wanna count just two days of that, not all four days.
Only the days in 2021
Is there any possibilty to limit the DATEDIFF calculation to 01/01/2021 AND 12/31/2021, but getting all requests affected in that year?
And how can I put that in one mysql-query? I can't find any solution on google for that.
Would be great, if someone had a similar problem and solved that.
Thank's in advance,
Tobias
I created a sample database like this (FIDDLE):
CREATE TABLE `holidays` (
`begin` date DEFAULT NULL,
`end` date DEFAULT NULL
)
INSERT INTO `holidays` VALUES
('2020-12-28','2021-01-05'),
('2020-12-05','2020-12-06'),
('2021-01-06','2021-01-06');
This SQL-statement:
select
begin,
CASE WHEN year(end)>year(begin) then ADDDATE(makedate(year(`end`),1),INTERVAL -1 DAY) else `end` end as END ,
year(begin) as year
from holidays
union all
select
makedate(year(`end`),1),
`end`,
year(`end`)
from holidays
where year(`begin`)<>year(`end`);
will have as output:
+------------+------------+------+
| begin | END | year |
+------------+------------+------+
| 2020-12-28 | 2020-12-31 | 2020 |
| 2020-12-05 | 2020-12-06 | 2020 |
| 2021-01-06 | 2021-01-06 | 2021 |
| 2021-01-01 | 2021-01-05 | 2021 |
+------------+------------+------+
BTW: One should never use, or at least try to avoid, reserved words in a table definition (like 'begin', 'end')
I have a table with laptimes. I'm looking for a way to find the lowest laptime at the time (ie a lap record), compared to earlier entries. I'm just learning MySQL for fun, and I am still a beginnner.
(I will use this to create a graph for the lap record over time.)
I have a table like this:
create table temp_laptimes(
lap_id INT NOT NULL,
driver VARCHAR(5) NOT NULL,
laptime FLOAT(5,1) NOT NULL,
lap_date DATE,
PRIMARY KEY ( lap_id )
);
INSERT INTO `temp_laptimes` (`lap_id`, `driver`, `laptime`, `lap_date`)
VALUES
('1', 'Dean', '56.8', '2019-01-01'),
('22', 'Zach', '59.7', '2019-02-01'),
('33', 'Carl', '56.1', '2019-03-01'),
('42', 'Zoe', '56.3', '2019-04-01'),
('50', 'Zach', '56.4', '2019-05-01'),
('61', 'Bob', '55.9', '2019-06-01'),
('73', 'Zeb', '56.2', '2019-07-01'),
('84', 'Anne', '55.7', '2019-08-01'),
('95', 'Dean', '55.9', '2019-09-01');
I want to find the lap records over time, ie a result like this:
1 Dean 56.8 2019-01-01
33 Carl 56.1 2019-03-01
61 Bob 55.9 2019-06-01
84 Anne 55.7 2019-08-01
Dean set the first laptime, so that's the first lap record. Then Carl beat that, then Bob beat that, and finally Anne beat that, holding the current record.
MySQL running on a shared host. As you see, lap_id is not continous.
I have tried things like this:
SELECT * FROM `temp_laptimes` t1
JOIN (
SELECT lap_id, driver, laptime, lap_date
FROM temp_laptimes
GROUP BY laptime
)
AS t2 ON t1.laptime < t2.laptime AND t1.lap_date > t2.lap_date
ORDER BY t1.laptime ASC
which apparently seems to find all occurences where a later laptime is lower than a previous laptime. For instance, Anne appears 7 times in the result, because she beat 7 different laptimes with her laptime. Bob appears 5 times. Zoe appears 1 time, cause she beat Zachs previous time.
But I don't know how to sort out just the lap records.
As I said, I'm a novice, and thankful for any help and pointers in the right direction. This is just a hobby project I'm doing for fun. Also, English is not my first language, so apologies if I'm unclear in my explanation. Thanks.
A NOT EXISTS condition with a correlated subquery would do the trick, like:
SELECT *
FROM temp_laptimes t
WHERE NOT EXISTS (
SELECT 1
FROM temp_laptimes t1
WHERE t1.lap_date < t.lap_date AND t1.laptime < t.laptime
)
The NOT EXISTS condition ensures that there is no previous record that has a smaller lap time.
Demo on DB Fiddlde:
| lap_id | driver | laptime | lap_date |
| ------ | ------ | ------- | ---------- |
| 1 | Dean | 56.8 | 2019-01-01 |
| 33 | Carl | 56.1 | 2019-03-01 |
| 61 | Bob | 55.9 | 2019-06-01 |
| 84 | Anne | 55.7 | 2019-08-01 |
If you are using MySQL 8.0, another, potentially more efficient method, is to use a window function in a subquery to compute the minimum lap time across the current and preceding record. Then, the outer query filters out on records where the minimum is equal to the current lap time:
SELECT *
FROM (
SELECT
t.*,
MIN(laptime) OVER(ORDER BY lap_date) min_lap_time
FROM temp_laptimes t
) x WHERE laptime = min_lap_time;
Demo on DB Fiddle (same results).
You can also use a correlated subquery for this:
select lt.*
from temp_laptimes lt
where lt.laptime = (select min(lt2.laptime)
from temp_laptimes lt2
where lt2.lapdate <= lt.lapdate
);
However, the cumulative window function suggested by gmb is better in MySQL 8+.
I have a simple INSERT statement which collects data from a simple html form and another mysql table and inserts all the data into a second mysql table.
mysqli_query($GLOBALS["conn"],
"INSERT INTO `Table2`
(idFI, NameSZ, ColorSZ, TimeSZ, RoomSZ, DateSZ)
SELECT id, FName, ColorFI, '$Time', '$Room', '$Date'
FROM Table1
WHERE id = '$FNameid'")
This works fine so far.
Now I want to add a statement which inserts a value (1, 2 or 3) into Table2 (RowSZ) depending on the time which was inserted in the input field for TimeSZ.
The rules:
below 8:00:00 --> Value 1
between 8:15:00 and 16:00:00 --> Value 2
above 16:15:00 --> Value 3
Example:
I type the time 12:00:00 into the input field (TimeSZ). When I click the submit button I want, together with the rest of the INSERT INTO statement, that it writes the value 2 into the row (RowSZ)
+------+--------+---------+----------+--------+------------+-------+
| idFi | NameSZ | ColorSZ | TimeSZ | RoomSZ | DateSZ | RowSZ |
+------+--------+---------+----------+--------+------------+-------+
| 33 | Namexx | #FFFFFF | 12:00:00 | 2 | 2018-06-30 | 2 |
The value 2 in RowSZ should be inserted automatically depending on the TimeSZ which was typed into the input field of the form.
How can I do it? Thanks!
This can be done in your SQL Insert statement. In your insert, you can calculate the value for RowSZ based on the time value:
INSERT INTO `Table2`
(idFI, NameSZ, ColorSZ, TimeSZ, RoomSZ, DateSZ, RowSZ)
SELECT id, FName, ColorFI, '$Time', '$Room', '$Date', IF('$time' < '08:00:00',1,if('$time' < '15:00:00',2,3))
FROM Table1
WHERE id = '$FNameid'
Let me start with, I am extremely new to SQL and I've been trying to figure this problem out for most of the week now. The database I'm pulling from is in phpmyadmin. What I have is a form, with several records, that I need to know which ones meet certain criteria. Specifically, I need to know which ones are Pending Approval and have been signed off on so I can mark them as Approved.
There are 11 different Signature Request fields (for different departments) that each have their own Signature field. I need to know which records have Signature Request fields marked as 'Approval' (meaning a signature is required from that department) and have a signature in the Signature field. On top of that, I also need it to only return records that are Pending Approval.
Basically the table looks like this:
+----+------------+--------+------------+--------+------------+--------+----------------+
| id | sign_rqst1 | sign1 | sign_rqst2 | sign2 | sign_rqst3 | sign3 |status |
+----+------------+--------+------------+--------+------------+--------+----------------+
| 1 | Approval | [sign] | | | Approval | [sign] |Pending Approval|
| 2 | | | Approval | [sign] | Approval | |Pending Approval|
| 3 | Approval | | Notice | | | |Pending Approval|
| 4 | Approval | [sign] | Approval | [sign] | | |Approved |
+----+------------+--------+------------+--------+------------+--------+----------------+
I need my query to return 1 and ignore 2, 3 & 4. But I can't figure out how to write the query to ignore records that don't fit the criteria. The AND and OR operators don't seem to be helping me in this scenario.
I've tried:
SELECT id
FROM table
WHERE sign_rqst1 IN ('Approval') AND sign1'' AND status = 'Pending Approval' AND
SELECT id
FROM table
WHERE sign_rqst2 IN ('Approval') AND sign2'' AND status = 'Pending Approval' AND
SELECT id
FROM table
WHERE sign_rqst3 IN ('Approval') AND sign3'' AND status = 'Pending Approval' AND
GROUP BY id;
This returns nothing, and OR returns everything.
Then I tried this (just using one set of columns to see if it would even work):
SELECT id
FROM table
WHERE sign_rqst1 IN ('Approval') AND status = 'Pending Approval'
GROUP BY id
HAVING COUNT(DISTINCT sign1'');
And it didn't parse out the ones that had no signature, so I got every record that had Approval marked in sign_rqst1.
I also tried a Temporary Table, but I couldn't even get that query to work.
I'm thinking I need to search for all the Approvals first, then use that to search for the Approvals that have signatures, but I have no idea how to do that and I haven't been able to find anything that helps. Any ideas?
EDIT: I should add that the signatures are actually image files. The program we use has a Signature Authority button that is replaced by a Signature image file when someone signs, so in the table it shows up as so-and-so.png so using <>'' to grab the fields that just have something in them is the only way I could figure out how to handle this mess.
CREATE TABLE `qms_engineering_change_order` (
`id` int(100) NOT NULL AUTO_INCREMENT,
`eng_action` text,
`eng_signature` text,
`eng_action2` text NOT NULL,
`eng_signature2` text NOT NULL,
`eng_signature3` text NOT NULL,
`eng_action3` text NOT NULL,
`eng_action4` text NOT NULL,
`eng_signature4` text NOT NULL,
`plan_action` text,
`plan_signature` text,
`sc_action` text,
`sc_signature` text,
`qa_action` text,
`qa_signature` text,
`oth_action` text,
`oth_signature` text,
`dcc_signature` text,
`dcc_signature` text,
`prod_signature` text,
`prod_action` text,
`sales_action` text,
`sales_signature` text,
Looks to me like the problem is in the way you're writing your query. Try using a query like this one:
SELECT *
FROM table
WHERE status = 'Pending Approval' AND (
sign_rqst1='Approval' AND sign1<>'' OR
sign_rqst2='Approval' AND sign2<>'' OR
sign_rqst3='Approval' AND sign3<>'');
[udpated to handle nulls]
Try the following:
SELECT *
FROM table
WHERE status = 'Pending Approval' AND
(
((ifnull(sign_rqst1,'') = 'Approval' AND ifnull(sign1,'')<>'') OR ifnull(sign_rqst1,'') = '') AND
((ifnull(sign_rqst2,'') = 'Approval' AND ifnull(sign2,'')<>'') OR ifnull(sign_rqst2,'') = '') AND
. . .
((ifnull(sign_rqst11,'') = 'Approval' AND ifnull(sign11,'')<>'') OR ifnull(sign_rqst11,'') = '')
)
ifnull(expr1, expr2) returns expr1 if it is not null, otherwise it returns expr2. This way I ensure that null strings are handled as empty strings: '' not NULL.
It seems my theory of creating a Temporary Table was the way to go, it just took me a while to figure out how to use the table to my advantage. I created the table to only show all of the Approval actions and their Signatures, compiled under two columns instead of 22.
CREATE TEMPORARY TABLE NeedApproval AS (
SELECT id, sign_rqst1 'ActionRequired', COALESCE(sign1) 'Signature'
FROM table
WHERE sign_rqst1 IN ('Approval') AND status = 'Pending Approval');
INSERT INTO NeedApproval
SELECT id, sign_rqst2 'ActionRequired', COALESCE(sign2) 'Signature'
FROM table
WHERE sign_rqst2 IN ('Approval') AND status = 'Pending Approval';
INSERT INTO NeedApproval
SELECT id, sign_rqst3 'ActionRequired', COALESCE(sign3) 'Signature'
FROM table
WHERE sign_rqst3 IN ('Approval') AND status = 'Pending Approval';
etc.. to include all of the fields. With my table looking more like this:
+----+------------+--------+
| id | sign_rqst1 | sign1 |
| 1 | Approval | [sign] |
| 1 | Approval | [sign] |
| 2 | Approval | [sign] |
| 2 | Approval | |
| 3 | Approval | |
+----+------------+--------+
Then I used a COUNT function (a more specific version of the one I'd tried before) to give me all of the records where all of the Approval actions had Signatures. This is the query I used on the Temporary Table:
SELECT id
FROM NeedApproval
GROUP BY id
HAVING COUNT(*) = SUM(CASE WHEN signature<>'' THEN 1 ELSE 0 END);
The database only has 166 records, so I was able to go through and manually check to see that it did what I needed. This worked perfectly, even if it took a little longer to work up than I'd anticipated.