Nested MySQL query hanging - mysql

I am working with the flights test data set.
CREATE TABLE IF NOT EXISTS `flights` (
`flightsKey` int(11) NOT NULL AUTO_INCREMENT,
`sno` varchar(10) DEFAULT NULL,
`year` int(4) DEFAULT NULL,
`month` int(2) DEFAULT NULL,
`day` varchar(10) DEFAULT NULL,
`dep_time` int(4) DEFAULT NULL,
`sched_dep_time` int(4) DEFAULT NULL,
`dep_delay` int(10) DEFAULT NULL,
`arr_time` int(4) DEFAULT NULL,
`sched_arr_time` int(4) DEFAULT NULL,
`arr_delay` int(10) DEFAULT NULL,
`carrier` varchar(2) DEFAULT NULL,
`flight` varchar(3) DEFAULT NULL,
`tailnum` varchar(10) NOT NULL,
`origin` varchar(3) DEFAULT NULL,
`dest` varchar(3) DEFAULT NULL,
`air_time` int(10) DEFAULT NULL,
`distance` int(10) DEFAULT NULL,
`hour` int(2) DEFAULT NULL,
`minute` int(3) DEFAULT NULL,
`fullDate` varchar(12) DEFAULT NULL,
PRIMARY KEY (`flightsKey`),
KEY `origin` (`origin`),
KEY `carrier` (`carrier`),
KEY `dest` (`dest`),
KEY `tailnum` (`tailnum`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=336868 ;
--
-- Dumping data for table `flights`
--
INSERT INTO `flights` (`flightsKey`, `sno`, `year`, `month`, `day`, `dep_time`, `sched_dep_time`, `dep_delay`, `arr_time`, `sched_arr_time`, `arr_delay`, `carrier`, `flight`, `tailnum`, `origin`, `dest`, `air_time`, `distance`, `hour`, `minute`, `fullDate`) VALUES
(1, '1', 2013, 1, '1', 517, 515, 2, 830, 819, 11, 'UA', '154', 'N14228', 'EWR', 'IAH', 227, 1400, 5, 15, '0000-00-00'),
(2, '2', 2013, 1, '1', 533, 529, 4, 850, 830, 20, 'UA', '171', 'N24211', 'LGA', 'IAH', 227, 1416, 5, 29, '0000-00-00'),
(3, '3', 2013, 1, '1', 542, 540, 2, 923, 850, 33, 'AA', '114', 'N619AA', 'JFK', 'MIA', 160, 1089, 5, 40, '0000-00-00'),
(4, '4', 2013, 1, '1', 544, 545, -1, 1004, 1022, -18, 'B6', '725', 'N804JB', 'JFK', 'BQN', 183, 1576, 5, 45, '0000-00-00'),
(5, '5', 2013, 1, '1', 554, 600, -6, 812, 837, -25, 'DL', '461', 'N668DN', 'LGA', 'ATL', 116, 762, 6, 0, '0000-00-00'),
(6, '6', 2013, 1, '1', 554, 558, -4, 740, 728, 12, 'UA', '169', 'N39463', 'EWR', 'ORD', 150, 719, 5, 58, '0000-00-00'),
(7, '7', 2013, 1, '1', 555, 600, -5, 913, 854, 19, 'B6', '507', 'N516JB', 'EWR', 'FLL', 158, 1065, 6, 0, '0000-00-00'),
(8, '8', 2013, 1, '1', 557, 600, -3, 709, 723, -14, 'EV', '570', 'N829AS', 'LGA', 'IAD', 53, 229, 6, 0, '0000-00-00'),
(9, '9', 2013, 1, '1', 557, 600, -3, 838, 846, -8, 'B6', '79', 'N593JB', 'JFK', 'MCO', 140, 944, 6, 0, '0000-00-00'),
(10, '10', 2013, 1, '1', 558, 600, -2, 753, 745, 8, 'AA', '301', 'N3ALAA', 'LGA', 'ORD', 138, 733, 6, 0, '0000-00-00');
I can get the query working by using views but I am trying to figure out what is causing my nested query to hang
This works without problem. Lets call it query 1:
SELECT carrier FROM flights GROUP BY carrier HAVING COUNT(*) <5000
it produces the following list:
('AS', 'F9','FL', 'HA', 'OO', 'YV')
This also works without problem. lets call it query 2.
SELECT origin, AVG(dep_delay) FROM flights
WHERE carrier IN ('AS', 'F9','FL', 'HA', 'OO', 'YV')
GROUP BY origin
However, when you use the query 1 as in inner query in query 2, it gets stuck:
SELECT origin, AVG(dep_delay) FROM flights
WHERE carrier IN (SELECT carrier FROM flights GROUP BY carrier HAVING COUNT(*) <5000)
GROUP BY origin
I also tried this and it worked without a hitch. I created a view for inner query:
CREATE view smallCarriers AS
SELECT carrier FROM flights GROUP BY carrier HAVING COUNT(*) <5000
Then I used the view as an inner query in the nested query:
SELECT origin, AVG(dep_delay) FROM flights
WHERE carrier IN (SELECT * FROM smallCarriers)
GROUP BY origin
Basically everything worked except for the explicit nested query.
I am running Mysql version 5.5.62 on Ubuntu 14.04. I am running these queries in phpmyadmin and the status of the query says "sending data" when it hangs.
I have included a link to the SQL fiddle here:
http://sqlfiddle.com/#!9/605236/5
It seems to work - so my question is why?
The actual table has 336776 rows. I tried both InnoDB and MyISAM thinking something was going on with the way the referential integrity was setup but I still have the same issue. What about this query causes the script to hang?
note - I have also tried the query from the mysql shell directly with the same result.
I have added the EXPLAIN result from the query which hangs:
mysql> EXPLAIN SELECT origin, AVG(dep_delay) FROM flights WHERE carrier IN (SELECT carrier FROM flights GROUP BY carrier HAVING COUNT(*) <5000) GROUP BY origin;
+----+--------------------+---------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+---------+-------+---------------+---------+---------+------+--------+-------------+
| 1 | PRIMARY | flights | index | NULL | origin | 12 | NULL | 337143 | Using where |
| 2 | DEPENDENT SUBQUERY | flights | index | NULL | carrier | 9 | NULL | 42183 | Using index |
+----+--------------------+---------+-------+---------------+---------+---------+------+--------+-------------+
2 rows in set (0.01 sec)

Related

Conditionally count the number of times a column in a row is one of a number of values?

Is there a native to MySQL method for building counts based on column value? My use case is as follows:
I have machines, employees, and products. Each time an employee interacts with one machine and one product, an entry is generated in a separate table called entries. Each machine has a type corresponding to the values of a table called stage. I want to use a complex query in order to count the number of times an employee has completed each stage.
My schema for each table is here:
entries table:
DROP TABLE IF EXISTS `entries`;
CREATE TABLE `entries` (
`Employee` int(200) NOT NULL,
`Product` varchar(45) NOT NULL,
`Machine` int(11) NOT NULL,
`DateTimeAdded` datetime DEFAULT NULL,
`TimeTaken` double DEFAULT NULL COMMENT 'The amount of time taken for each entry to be processed'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `entries` (`Employee`, `Product`, `Machine`, `DateTimeAdded`, `TimeTaken`) VALUES
(1, '365', 1, '2020-11-13 11:55:15', 0.0094444444444444),
(1, '365', 5, '2020-11-13 11:55:49', 2.6069444444444),
(1, '1', 1, '2020-11-13 14:21:45', 0.019722222222222),
(1, '4', 1, '2020-11-13 14:22:56', 0.071388888888889),
(1, '2', 1, '2020-11-13 14:27:13', 0.066666666666667),
(1, '3', 1, '2020-11-13 14:31:13', 0.064722222222222),
(1, '2', 5, '2020-11-13 14:32:14', 0.015555555555556),
(1, '2', 8, '2020-11-13 14:33:10', 0.080277777777778),
(1, '3', 2, '2020-11-13 14:35:06', 0.0036111111111111),
(1, '4', 2, '2020-11-13 14:35:19', 0.012777777777778),
(1, '4', 6, '2020-11-13 14:36:05', 0.18944444444444),
(1, '1', 5, '2020-11-13 14:43:08', 115.66777777778),
(1, '4', 9, '2020-11-13 14:47:27', 0.012222222222222),
(1, '2', 9, '2020-11-13 14:48:11', 115.58861111111),
(1, '1', 1, '2020-11-18 10:23:12', NULL),
(1, '2', 1, '2020-11-18 10:23:30', 2.8641666666667),
(1190, '2', 5, '2020-11-18 13:15:21', 0.01),
(1190, '2', 8, '2020-11-18 13:15:57', 0.28361111111111),
(1190, '6', 14, '2020-11-18 13:26:36', NULL);
User (employee) table:
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`Username` int(200) NOT NULL,
`Password` varchar(45) NOT NULL,
`DateHired` datetime NOT NULL,
`JobRole` varchar(45) DEFAULT NULL,
`Status` varchar(45) NOT NULL,
`FirstName` varchar(45) NOT NULL,
`LastName` varchar(45) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `user` (`Username`, `Password`, `DateHired`, `JobRole`, `Status`, `FirstName`, `LastName`) VALUES
(1, '1', '2020-02-02 12:22:11', 'Manager', 'FullTime', 'Manager', 'User'),
(10, '1', '2020-01-01 00:00:00', 'Viewer', 'fulltime', 'Viewer', 'User'),
(1190, '1', '2020-08-04 00:00:00', 'Employee', 'partTime', 'Employee', 'User'),
(1198, '67f7a304c32875eadc0f', '2020-11-19 00:00:00', 'Employee', '', 'Eric', 'Wise');
Stage table:
DROP TABLE IF EXISTS `stage`;
CREATE TABLE `stage` (
`StageID` int(11) NOT NULL,
`StageName` varchar(45) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `stage` (`StageID`, `StageName`) VALUES
(1, 'Pre-Inspection'),
(2, 'Pre-Washing (Jig-Washer)'),
(3, 'Stripping (Shot)'),
(4, 'Stripping (Liquid)'),
(5, 'WPC-SKH'),
(6, 'WPC-Ceramic'),
(7, 'Pre-Lapping (SMAP)'),
(8, 'Pre-Lapping (AERO)'),
(9, 'Pre-Lapping (Hand Lapping)'),
(10, 'Pre-Washing (F1 Clean Washer)'),
(11, 'Coating (M1) - Set/Disassemble'),
(12, 'Coating (M2) - Set/Disassemble'),
(13, 'Coating (M3) - Set/Disassemble'),
(14, 'Post-Inspection'),
(15, 'Post-Lapping (SMAP)'),
(16, 'Post-Lapping (AERO)'),
(17, 'Post-Lapping (Hand Lapping)'),
(18, 'Final Inspection'),
(19, 'Packing/Shipping');
Machine table:
DROP TABLE IF EXISTS `machine`;
CREATE TABLE `machine` (
`MachineID` int(11) NOT NULL,
`NumberOfTimesUsed` int(11) DEFAULT NULL,
`MachineType` varchar(45) DEFAULT NULL,
`HoursUptime` double UNSIGNED NOT NULL DEFAULT 0 COMMENT 'the number of hours a machine has been used',
`LastMaintenanceDate` date DEFAULT NULL,
`MachineAutoTime` int(11) DEFAULT NULL COMMENT 'The time a machine runs without human interaction'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `machine` (`MachineID`, `NumberOfTimesUsed`, `MachineType`, `HoursUptime`, `LastMaintenanceDate`, `MachineAutoTime`) VALUES
(1, 0, 'Pre-Inspection', 2.8641666666667, '2020-11-13', 0),
(2, 0, 'Pre-Washing (Jig-Washer)', 45.8408333333339, NULL, 0),
(3, 0, 'Stripping (Shot)', 25.089722222222672, NULL, 0),
(4, 0, 'Stripping (Liquid)', 0, NULL, 0),
(5, 0, 'WPC-SKH', 0, '2020-11-18', 0),
(6, 0, 'WPC-Ceramic', 0.18944444444444, NULL, 0),
(7, 0, 'Pre-Lapping (SMAP)', 0, NULL, 0),
(8, 0, 'Pre-Lapping (AERO)', 0.363888888888888, NULL, 0),
(9, 0, 'Pre-Lapping (Hand Lapping)', 115.62416666666556, '2020-11-08', 0),
(10, 0, 'Pre-Washing (F1 Clean Washer)', 0, NULL, 0),
(11, 0, 'Coating (M1) - Set/Disassemble', 0, NULL, 0),
(12, 0, 'Coating (M2) - Set/Disassemble', 0, NULL, 0),
(13, 0, 'Coating (M3) - Set/Disassemble', 0, NULL, 0),
(14, 0, 'Post-Inspection', 0, NULL, 0),
(15, 0, 'Post-Lapping (SMAP)', 23.692222222222, NULL, 0),
(16, 0, 'Post-Lapping (AERO)', 0, NULL, 0),
(17, 0, 'Post-Lapping (Hand Lapping)', 0, NULL, 0),
(18, 0, 'Final Inspection', 0, NULL, 0),
(19, 0, 'Packing/Shipping', 44.83916666666622, NULL, 0);
The logic is as follows:
Pull the stage names from the table
pull the machine from the entry table where ID is the employee I am looking for
loop through the entry results, adding counts to variables based on if MachineType is equal to StageName
I wanted to know if there is a native way to do this in MySQL or if I need to pull all the information and do the counting inside of the back-end server code.
So far my train of thought is to use some sort of case statement inside of the SQL statement. I am very new to SQL, so I am not sure where to begin on formatting such a query. Does this sound like the right direction?
The expected results are as follows:
+----------+----------------+--------------------------+------------------+--------------------+---------+-------------+--------------------+--------------------+----------------------------+-------------------------------+--------------------------------+--------------------------------+--------------------------------+-----------------+---------------------+---------------------+-----------------------------+------------------+------------------+
| Employee | Pre-Inspection | Pre-Washing (Jig-Washer) | Stripping (Shot) | Stripping (Liquid) | WPC-SKH | WPC-Ceramic | Pre-Lapping (SMAP) | Pre-Lapping (AERO) | Pre-Lapping (Hand Lapping) | Pre-Washing (F1 Clean Washer) | Coating (M1) - Set/Disassemble | Coating (M2) - Set/Disassemble | Coating (M3) - Set/Disassemble | Post-Inspection | Post-Lapping (SMAP) | Post-Lapping (AERO) | Post-Lapping (Hand Lapping) | Final Inspection | Packing/Shipping |
+----------+----------------+--------------------------+------------------+--------------------+---------+-------------+--------------------+--------------------+----------------------------+-------------------------------+--------------------------------+--------------------------------+--------------------------------+-----------------+---------------------+---------------------+-----------------------------+------------------+------------------+
| 1 | 7 | 2 | 0 | 0 | 3 | 0 | 0 | 1 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+----------+----------------+--------------------------+------------------+--------------------+---------+-------------+--------------------+--------------------+----------------------------+-------------------------------+--------------------------------+--------------------------------+--------------------------------+-----------------+---------------------+---------------------+-----------------------------+------------------+------------------+
| 1190 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
+----------+----------------+--------------------------+------------------+--------------------+---------+-------------+--------------------+--------------------+----------------------------+-------------------------------+--------------------------------+--------------------------------+--------------------------------+-----------------+---------------------+---------------------+-----------------------------+------------------+------------------+

MySQL. Average price, connecting two databases

I am learning MySQL and I currently do not understand how to do something.
I have two tables and I want to display some stuff out of it, it's pretty hard to explain so I'd rather show you.
These are my tables:
CREATE TABLE IF NOT EXISTS `proprietate` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`serie_buletin` varchar(8) NOT NULL,
`cnp` bigint(20) NOT NULL,
`nr_vehicul` int(11) NOT NULL,
`data_cumpararii` date NOT NULL,
`pret` int(11) NOT NULL,
`id_persoana` int(11) NOT NULL,
PRIMARY KEY (id),
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=16 ;
CREATE TABLE IF NOT EXISTS `vehicul` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nr_vehicul` int(11) NOT NULL,
`marca` varchar(30) NOT NULL,
`id_marca` int(11) NOT NULL,
`tip` varchar(15) NOT NULL,
`culoare` varchar(15) NOT NULL,
`capacitate_cilindrica` int(11) NOT NULL,
`id_proprietate` int(11) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id_proprietate) REFERENCES proprietate(id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=16 ;
And these are my values inside my tables:
INSERT INTO `proprietate` (`id`, `serie_buletin`, `cnp`, `nr_vehicul`, `data_cumpararii`, `pret`, `id_persoana`) VALUES
(1, 'AK162332', 2006036035087, 4, '2014-05-01', 35000, 1),
(2, 'AK162332', 2006036035087, 10, '2014-05-02', 90000, 2),
(3, 'AK176233', 6548751520125, 2, '2014-05-03', 55000, 3),
(4, 'BZ257743', 6548751520125, 2, '2014-05-04', 25000, 4),
(5, 'BZ257743', 2006036035087, 15, '2014-05-05', 63000, 5),
(6, 'DC456542', 2003564784513, 7, '2014-05-06', 30000, 6),
(7, 'EN654872', 2012654879521, 6, '2014-05-07', 50000, 7);
INSERT INTO `vehicul` (`id`, `nr_vehicul`, `marca`, `id_marca`, `tip`, `culoare`, `capacitate_cilindrica`, `id_proprietate`) VALUES
(1, 4, 'Mercedes', 1, 'CLK 350', 'negru', 3500, 1),
(2, 10, 'Mercedes', 1, 'S 500', 'silver', 5000, 2),
(3, 2, 'Mercedes', 1, 'ML 550', 'alb', 5500, 3),
(4, 2, 'BMW', 2, '325', 'galben', 2500, 4),
(5, 15, 'BMW', 2, 'X5', 'negru', 3500, 5),
(6, 7, 'Audi', 3, 'R5', 'mov', 5000, 6),
(7, 6, 'Audi', 3, 'Q5', 'metalic', 3000, 7);
What I want to display is:
marca | nr_vehicul | average_price
Audi | 13 | 40000
BMW | 17 | 44000
Mercedes | 16 | 60000
How can I do that? So far I have managed to display the first two columns but I have no idea how to reference the first table in the second and calculate the average price.
This is what I have so far:
SELECT marca, SUM(nr_vehicul) AS nr_vehicul FROM vehicul GROUP BY marca
Can anyone help me please?
You should join your tables to get combined information from both of them:
SELECT marca, SUM(vehicul.nr_vehicul) AS nr_vehicul, avg(pret) as pret
FROM vehicul
LEFT OUTER JOIN proprietate on (id_proprietate = proprietate.id)
GROUP BY marca;
see this sql fiddle session for the output.
First you select the data (column names with appropriate functions used) you need: marca, SUM(vehicul.nr_vehicul), AVG(pret), then you construct the joined structure from where mysql should retrieve these informations: vehicul, proprietate.
For this structure you need primarily the vehicul table, by which you will group the result set. You want to join the proprietate table to the vehicul table properly, to make sure the correct data structure is created. Since you have foreign key from one table to the other, the easiest way to do it is to use that key: LEFT OUTER JOIN proprietate on (id_proprietate = proprietate.id).
For more information on understanding the different JOIN types, please see this article by Craig Buckler.
$query = "SELECT type, AVG(pret) FROM vehicul GROUP BY marca";
$result = mysql_query($query) or die(mysql_error());
// Print out result
while($row = mysql_fetch_array($result)){
echo "The average price of ". $row['type']. " is $".$row['AVG(price)'];}</code>
should return the average price per marca

mySQL Divide two values from Same Column

I wish to divide values from the same column using mySQL.
is there a better way of doing this??? Do I really need 3 select statements?
SELECT (SELECT FixAM From Fixes WHERE Id = 1) / (SELECT FixAM From Fixes WHERE Id = 2)
My table structure is as follows:
CREATE TABLE IF NOT EXISTS `Fixes` (
`Id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'PK',
`CurrencyId` int(11) NOT NULL COMMENT 'FK',
`MetalId` int(11) NOT NULL COMMENT 'FK',
`FixAM` decimal(10,5) NOT NULL,
`FixPM` decimal(10,5) DEFAULT NULL,
`TimeStamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `CurrencyId` (`CurrencyId`),
KEY `MetalId` (`MetalId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=13 ;
--
-- Dumping data for table `Fixes`
--
INSERT INTO `Fixes` (`Id`, `CurrencyId`, `MetalId`, `FixAM`, `FixPM`, `TimeStamp`) VALUES
(1, 1, 1, '1592.50000', '1586.25000', '2013-02-25 15:10:21'),
(2, 2, 1, '1051.84900', '1049.59300', '2013-02-25 15:10:21'),
(3, 3, 1, '1201.88700', '1194.10600', '2013-02-25 15:10:21'),
(4, 1, 2, '29.17000', NULL, '2013-02-25 13:54:02'),
(5, 2, 2, '19.27580', NULL, '2013-02-25 13:54:02'),
(6, 3, 2, '21.98190', NULL, '2013-02-25 13:54:02'),
(7, 1, 3, '1627.00000', '1620.00000', '2013-02-25 14:28:59'),
(8, 2, 3, '1074.65000', '1072.50000', '2013-02-25 14:28:59'),
(9, 3, 3, '1229.30000', '1218.95000', '2013-02-25 14:28:59'),
(10, 1, 4, '747.00000', '748.00000', '2013-02-25 14:28:59'),
(11, 2, 4, '493.40000', '495.20000', '2013-02-25 14:28:59'),
(12, 3, 4, '564.40000', '562.85000', '2013-02-25 14:28:59');
I think this is what you're looking for:
SELECT MetalId,
MAX(CASE WHEN CurrencyId = 1 THEN FixAM END) /
MAX(CASE WHEN CurrencyId = 2 THEN FixAM ELSE 1 END) Output
FROM Fixes
GROUP BY MetalId
This produces 1592.50000 / 1051.849000. If you want the opposite, swap the currency ids.
SQL Fiddle Demo
In case you don't have a CurrencyId = 2, I defaulted the dividing value to 1 so you wouldn't receive an error.

How to count date difference excluding weekend and holidays in MySQL

I need to count days (business days) between two dates excluding weekend (most important) and holidays
SELECT DATEDIFF(end_date, start_date) from accounts
But, I don't know how am I supposed to do it in MySQL, I found this article Count days between two dates, excluding weekends (MySQL only). I cannot figure out how to functional query in mysql, Can you give some information of how can achieve this with mysql query. If I am missing anything let me know.
[EDIT]
CREATE TABLE `candidatecase` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Unique ID',
`CreatedBy` int(11) NOT NULL,
`UseraccountID` int(11) NOT NULL COMMENT 'User Account ID',
`ReportReadyID` int(11) DEFAULT NULL COMMENT 'Report Ready ID',
`DateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date Created',
`InitiatedDate` timestamp NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Date Initiated',
`ActualCompletedDate` timestamp NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Date Completed Case',
`ProjectedCompletedDate` timestamp NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Date Projected Finish',
`CheckpackagesID` int(11) DEFAULT NULL COMMENT 'Default Check Package Auto Assign Once Initiate Start',
`Alacartepackage1` int(11) DEFAULT NULL COMMENT 'Ala carte Request #2',
`Alacartepackage2` int(11) DEFAULT NULL COMMENT 'Ala carte Request #3',
`OperatorID` int(11) NOT NULL COMMENT 'User Account - Operator',
`Status` int(11) NOT NULL COMMENT 'Status',
`caseRef` varchar(100) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=293 ;
--
-- Dumping data for table `candidatecase`
--
INSERT INTO `candidatecase` (`ID`, `CreatedBy`, `UseraccountID`, `ReportReadyID`, `DateCreated`, `InitiatedDate`, `ActualCompletedDate`, `ProjectedCompletedDate`, `CheckpackagesID`, `Alacartepackage1`, `Alacartepackage2`, `OperatorID`, `Status`, `caseRef`) VALUES
(1, 43, 70, NULL, '2011-07-22 02:29:31', '2011-07-07 07:27:44', '2011-07-22 02:29:31', '2011-07-17 06:53:52', 11, NULL, NULL, 44, 6, ''),
(2, 43, 74, NULL, '2012-04-03 04:17:15', '2011-07-11 07:07:23', '2011-07-13 05:32:58', '2011-07-21 07:01:34', 20, 0, 0, 51, 0, ''),
(3, 43, 75, NULL, '2011-07-29 04:10:07', '2011-07-11 07:27:12', '2011-07-29 04:10:07', '2011-07-21 07:02:14', 20, NULL, NULL, 45, 6, ''),
(4, 43, 78, NULL, '2011-07-18 03:32:27', '2011-07-11 07:51:31', '2011-07-13 02:18:34', '2011-07-21 07:37:53', 20, NULL, NULL, 45, 6, ''),
(5, 43, 76, NULL, '2011-07-29 04:09:19', '2011-07-11 07:51:11', '2011-07-29 04:09:19', '2011-07-21 07:38:30', 20, NULL, NULL, 45, 6, ''),
(6, 43, 77, NULL, '2011-07-18 03:32:49', '2011-07-11 07:51:34', '2011-07-18 02:18:46', '2011-07-21 07:39:00', 20, NULL, NULL, 45, 6, ''),
(7, 43, 79, NULL, '2011-07-18 03:33:02', '2011-07-11 07:53:24', '2011-07-18 01:50:12', '2011-07-21 07:42:57', 20, NULL, NULL, 45, 6, ''),
(8, 43, 80, NULL, '2011-07-29 04:10:38', '2011-07-11 07:53:58', '2011-07-29 04:10:38', '2011-07-21 07:43:14', 20, NULL, NULL, 45, 6, ''),
(9, 43, 81, NULL, '2011-07-18 03:31:54', '2011-07-11 07:53:49', '2011-07-13 02:17:02', '2011-07-21 07:43:43', 20, NULL, NULL, 45, 6, ''),
(11, 43, 88, NULL, '2011-07-18 03:15:53', '2011-07-13 04:57:38', '2011-07-15 08:57:15', '2011-07-23 04:39:14', 12, NULL, NULL, 44, 6, ''),
(13, 43, 90, NULL, '2011-07-26 07:39:24', '2011-07-13 12:16:48', '2011-07-26 07:39:24', '2011-07-23 12:13:50', 15, NULL, NULL, 51, 6, ''),
(63, 43, 176, NULL, '2011-09-13 08:23:13', '2011-08-26 10:00:32', '2011-09-13 08:23:13', '2011-09-05 09:58:47', 41, NULL, NULL, 45, 6, ''),
(62, 43, 174, NULL, '2011-08-24 03:54:30', '2011-08-24 03:53:13', '2011-08-24 03:54:30', '2011-08-29 03:52:48', 17, NULL, NULL, 51, 6, ''),
(61, 43, 173, NULL, '2011-08-24 03:55:05', '2011-08-24 03:53:39', '2011-08-24 03:55:05', '2011-08-29 03:52:36', 17, NULL, NULL, 51, 6, ''),
(60, 43, 172, NULL, '2011-08-24 03:22:41', '2011-08-24 03:21:50', '2011-08-24 03:22:41', '2011-08-29 03:21:11', 17, NULL, NULL, 51, 6, ''),
(59, 43, 171, NULL, '2011-08-24 03:23:19', '2011-08-24 03:22:00', '2011-08-24 03:23:19', '2011-08-29 03:20:57', 17, NULL, NULL, 51, 6, '');
You might want to try this:
Count the number of working days (took it from here)
SELECT 5 * (DATEDIFF('2012-12-31', '2012-01-01') DIV 7) + MID('0123444401233334012222340111123400012345001234550', 7 * WEEKDAY('2012-01-01') + WEEKDAY('2012-12-31') + 1, 1)
This gives you 261 working days for 2012.
Now you need to know your holidays that are not on a weekend
SELECT COUNT(*) FROM holidays WHERE DAYOFWEEK(holiday) < 6
The result of this depends on your holiday table.
We need to get that in one query:
SELECT 5 * (DATEDIFF('2012-12-31', '2012-01-01') DIV 7) + MID('0123444401233334012222340111123400012345001234550', 7 * WEEKDAY('2012-01-01') + WEEKDAY('2012-12-31') + 1, 1) - (SELECT COUNT(*) FROM holidays WHERE DAYOFWEEK(holiday) < 6)
This should be it.
Edit: Please be aware that this only works properly if your end date is higher than your start date.
Create a table that contains all the weekends and holidays for the next 100whatever years.
You need to be able to specify when a day is a 'holiday' given that no one knows what the holidays will be for 2052 yet, you will not be able to make an accurate function at this time anyway. just update your non-work day table each year when the holidays become known (but you will always know the weekends).
Then your query becomes:
SELECT DATEFIFF(end_date, start_date) - COALESCE((SELECT COUNT(1) FROM nonWorkDays WHERE nonWorkDays.date BETWEEN start_date AND end_date), 0)
FROM accounts
If you really need to write a DATEDIFFWITHOUTWEEKENDSORHOLIDAYS function then just use the above and create a function (there's plenty of resources on how to make functions in each RDBMS).. just be sure to give it a better name. ^_^
One thing you will need to fix is I think there's a +1 missing somewhere in the above, for example DATEDIFF(today, today) if today is a weekend will return -1 instead of returning 0.
Something like this may work. Add all holiday dates and weekend dates to a table.
SELECT
DATEDIFF(end_date, start_date)
FROM table
WHERE date NOT IN (SELECT date FROM holidaydatestable )
Try This Code this will Calculate no of days Excluding Weekends
SELECT
(DATEDIFF(dd, #StartDate, #EndDate)+1)
-(DATEDIFF(wk, #StartDate, #EndDate) * 2)
from test_tbl where date NOT IN (SELECT date FROM holidaydatestable )
Make a function that will make a while cycle between the dates incrementing the number of days when it's not a saturday or sunday.

Alternative to subquery

Given the following tables:
CREATE TABLE IF NOT EXISTS `rank` (
`rank_id` bigint(20) NOT NULL AUTO_INCREMENT,
`rank` int(10) NOT NULL DEFAULT '0',
`subject_id` int(10) NOT NULL DEFAULT '0',
`title_id` int(10) NOT NULL DEFAULT '0',
`source_id` int(10) NOT NULL DEFAULT '0'
PRIMARY KEY (`rank_id`)
) ENGINE=MyISAM;
INSERT INTO `rank` (`rank_id`, `rank`, `subject_id`, `title_id`, `source_id`) VALUES
(23, 0, 2, 1, 1),
(22, 0, 1, 1, 1),
(15, 0, 2, 2, 2),
(14, 0, 2, 2, 1),
(20, 0, 1, 3, 2),
(18, 0, 1, 4, 2),
(19, 0, 1, 5, 2),
(21, 0, 1, 3, 1),
(24, 0, 1, 6, 2);
CREATE TABLE IF NOT EXISTS `title` (
`title_id` bigint(20) NOT NULL AUTO_INCREMENT,
`title` varchar(255) DEFAULT NULL,
`description` text,
`pre` varchar(255) DEFAULT NULL,
`last_modified_by` varchar(50) DEFAULT NULL,
`last_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`title_id`)
) ENGINE=MyISAM;
INSERT INTO `title` (`title_id`, `title`, `last_modified`) VALUES
(1, 'new item', ' ', '2011-10-20 19:10:48'),
(2, 'another test', '2011-10-20 19:10:48'),
(3, 'and yet another', '2011-10-20 19:10:48'),
(4, 'one more', ' ', '2011-10-20 19:10:48'),
(5, 'adding more', ' ', '2011-10-20 19:10:48'),
(6, 'yes, another', ' ', '2011-10-20 19:10:48'),
(7, 'well, let''s see', ' ', '2011-10-20 19:10:48');
My need is for a query to select all titles that are not connected to a given subject in the rank table.
I have this working via a subquery:
SELECT title_id, title FROM title
WHERE title_id NOT IN (SELECT title_id FROM rank WHERE subject_id=2)
This returns the desired list:
+----------+-----------------+
| title_id | title |
+----------+-----------------+
| 3 | and yet another |
| 4 | one more |
| 5 | adding more |
| 6 | yes, another |
| 7 | well, let's see |
+----------+-----------------+
However, it gets a little slow when a large set of data is queried.
My question is if there is a way to return this result without the use of a subquery and if this alternative is any speedier.
Thanks in advance.
MySQL is usually faster with joins, though faster sub-queries are work in progress.
SELECT t.*
FROM title AS t
LEFT JOIN rank AS r ON (t.title_id = r.title_id AND r.subject_id = 2)
WHERE r.title_id IS NULL
As usual, you'll need to set up indexes on the foreign key (rank.title_id) and probably on the queried key (rank.subject_id).
You should read the MySQL documentation on [LEFT JOIN][1] if you want more details. There's also a nice trick with ONthat makes it different from WHERE.
The MySQL EXPLAIN command will tell you where your query needs help. e.g. EXPLAIN select title_id, title FROM title WHERE title_id NOT IN (select title_id from rank where subject_id=2)
My guess is that the true problem is that you don't have an index on rank.subject_id and that's causing a table scan (when rank has lots of rows).
Please create two indexes on subject_id and title_id and try the same.