Im currently have room availability present which displays current open rooms for bookings given a specified date range.
I need to display the same availability but instead of displaying rooms for the FULL availability i need to show partial availability.
Eg: booking 1 is from dates 22nd to 25th (within room 4)
booking 2 is from dates 24th to 28th (within room 3)
queried booking is from 23rd till 25th
22nd 23rd 24th 25th 28th
|-----------------------|
|------------------|
|------| free space
query:
SELECT r.*
, CASE WHEN b.ref IS NULL THEN 'all' ELSE 'partial' END status
FROM roominfo r
LEFT JOIN bookroom br ON br.id = r.id
LEFT JOIN book b ON b.ref = br.ref
AND b.end_date >= '2019-11-23' AND b.start_date <= '2019-11-25'
ORDERBY r.id;
example structure & data:
CREATE SCHEMA TEST;
USE TEST;
CREATE TABLE BOOK( Ref INT NOT NULL AUTO_INCREMENT, Start_Date DATE NOT NULL, End_Date DATE NOT NULL, PRIMARY KEY(Ref));
CREATE TABLE ROOMINFO( ID INT NOT NULL AUTO_INCREMENT, `Type` VARCHAR(10) NOT NULL, Max TINYINT NOT NULL, PRIMARY KEY(ID));
CREATE TABLE BOOKROOM( Ref INT NOT NULL,ID INT NOT NULL, FOREIGN KEY (Ref) REFERENCES BOOK(Ref), FOREIGN KEY (ID) REFERENCES ROOMINFO(ID));
INSERT INTO BOOK(Start_Date, End_Date) VALUES
('2019-11-22', '2019-11-25'),('2019-11-24', '2019-11-28'),('2019-12-01', '2019-12-02'),('2019-12-01', '2019-12-06'),
('2019-12-02', '2019-12-03'),('2019-12-04', '2019-12-10'),('2019-12-04', '2019-12-10'),('2019-12-05', '2019-12-13'),
('2019-12-16', '2019-12-19'),('2019-12-26', '2019-12-28'),('2019-12-26', '2020-01-01'),('2019-12-28', '2020-01-02'),
('2019-12-31', '2020-01-05'),('2020-01-03', '2020-01-08'),('2020-01-05', '2020-01-11'),('2020-01-06', '2020-01-09'),
('2020-01-06', '2020-01-11'),('2020-01-08', '2020-01-18'),('2020-01-11', '2020-01-15'),('2020-01-15', '2020-01-17'),
('2020-01-15', '2020-01-18');
INSERT INTO ROOMINFO (ID, `Type`,Max) VALUES
(1, "Family", 4), (2, "Family", 4), (3, "Family", 4), (4, "Dual", 2),
(5, "Dual", 2), (6, "Dual", 2), (7, "Dual", 2), (8, "Dual", 2),
(9, "Dual", 2), (10, "Dual", 2);
INSERT INTO BOOKROOM( Ref, ID ) VALUES
(1, 4), (2, 3), (3, 4), (4, 5),(5, 6), (6, 7), (7, 3), (8, 2), (9, 1), (10, 8),(11, 3),
(12, 9), (13, 2), (14, 10), (15, 4), (16, 5), (17, 6), (18, 7), (19, 2),(20, 1), (21, 10);
desired output:
id (& some indication of partial availability?)
1 all
2 all
3 partial
4 partial
5 all
6 all
7 all
8 all
9 all
10 all
Ignoring the distressing naming policy...
DROP TABLE IF EXISTS book;
CREATE TABLE BOOK( Ref INT NOT NULL AUTO_INCREMENT, Start_Date DATE NOT NULL, End_Date DATE NOT NULL, PRIMARY KEY(Ref));
DROP TABLE IF EXISTS roominfo;
CREATE TABLE ROOMINFO( ID INT NOT NULL AUTO_INCREMENT, `Type` VARCHAR(10) NOT NULL, capacity TINYINT NOT NULL, PRIMARY KEY(ID));
DROP TABLE IF EXISTS bookroom;
CREATE TABLE BOOKROOM( Ref INT NOT NULL,ID INT NOT NULL);
INSERT INTO BOOK(Start_Date, End_Date) VALUES
("2019-11-03", "2019-11-10"), ("2019-11-05", "2019-11-13");
INSERT INTO ROOMINFO (ID, `Type`,capacity) VALUES
(1, "Family", 4), (2, "Family", 4), (3, "Family", 4), (4, "Dual", 2),
(5, "Dual", 2), (6, "Dual", 2), (7, "Dual", 2), (8, "Dual", 2),
(9, "Dual", 2), (10, "Dual", 2);
INSERT INTO BOOKROOM( Ref, ID ) VALUES (1, 4), (2, 3);
SELECT r.*
, CASE WHEN b.ref IS NULL THEN 'all' ELSE 'partial' END status
FROM roominfo r
LEFT
JOIN bookroom br
ON br.id = r.id
LEFT
JOIN book b
ON b.ref = br.ref
AND b.end_date >= '2019-11-01' AND b.start_date <= '2019-11-13'
ORDER
BY r.id;
+----+--------+----------+---------+
| ID | Type | capacity | status |
+----+--------+----------+---------+
| 1 | Family | 4 | all |
| 2 | Family | 4 | all |
| 3 | Family | 4 | partial |
| 4 | Dual | 2 | partial |
| 5 | Dual | 2 | all |
| 6 | Dual | 2 | all |
| 7 | Dual | 2 | all |
| 8 | Dual | 2 | all |
| 9 | Dual | 2 | all |
| 10 | Dual | 2 | all |
+----+--------+----------+---------+
Related
My schema looks like this:
SET GLOBAL sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''));
create table ads(
ad_id int,
ad_name varchar(10)
);
create table ads_insight(
id int,
ad_id int,
date date,
ad_clicks int
);
create table products(
id int,
name varchar(10)
);
create table products_insight(
id int,
product_id int,
sale int,
date date
);
create table ads_products(
ad_id int,
product_id int
);
insert into ads(ad_id, ad_name) values
(1,'ad1'),
(2,'ad2'),
(3,'ad3');
insert into ads_insight(id, ad_id, date, ad_clicks) values
(1, 1, '2021-04-25', 1),
(3, 1, '2021-04-23', 2),
(4, 1, '2021-04-22', 8),
(5, 2, '2021-04-25', 6),
(6, 2, '2021-03-03', 7);
insert into products(id, name) values
(1,'prod1'),
(2,'prod2'),
(3,'prod3'),
(4,'prod4'),
(5,'prod5');
insert into products_insight(id, product_id, sale, date) values
(1, 1, 10, '2021-04-25'),
(2, 1, 13, '2021-04-24'),
(3, 1, 15, '2021-04-23'),
(4, 1, 14, '2021-04-22'),
(5, 1, 17, '2021-04-21'),
(6, 1, 15, '2021-04-20'),
(7, 1, 13, '2021-04-19'),
(8, 2, 15, '2021-04-25');
insert into ads_products (ad_id, product_id) values
(1, 1),
(1, 2),
(2, 3),
(2, 4),
(2, 2),
(3, 1);
Here you have fiddle
A quick explanation of schema:
I have ads:
each ad has insights, which tell us when a certain ad was active(=> ad_clicks has to be > 0).
each ad has products(many2many - ads_products table). Each product has products_insight which tells us how many sales that product generated on a certain day.
Now I want to get all ads from the time range 2021-04-20 - 2021-04-25 which had ad_clicks > 0 (which I have done) AND count how many sales each ad has generated when it was active. So count sale only if the ad has ad_insight and ad_clicks > 0.
My query looks like this:
SET #from_date = '2021-04-20';
SET #to_date = '2021-04-25';
SELECT
ads.ad_name,
IFNULL(ad_clicks, 0) AS clicks,
IFNULL(product_sale, 0) AS product_sale,
IFNULL(products, '') AS products
FROM ads
LEFT JOIN (
SELECT ad_id, SUM(ad_clicks) AS ad_clicks
FROM ads_insight
WHERE date BETWEEN #from_date AND #to_date
GROUP BY ad_id
) AS ai ON ai.ad_id = ads.ad_id
LEFT JOIN (
SELECT ad_id, SUM(sale) AS product_sale
FROM ads_products AS ap
LEFT JOIN products_insight AS pi ON pi.product_id = ap.product_id
WHERE date BETWEEN #from_date AND #to_date
GROUP BY ad_id
) AS pi ON pi.ad_id = ads.ad_id
LEFT JOIN (
SELECT ap.ad_id, GROUP_CONCAT(DISTINCT p.name) AS products
FROM ads_products AS ap
JOIN products AS p ON ap.product_id = p.id
GROUP BY ap.ad_id
) AS p ON ads.ad_id = p.ad_id
WHERE ad_clicks>0;
And it generates the following result:
| ad_name | clicks | product_sale | products |
| ------- | ------ | ------------ | ----------------- |
| ad1 | 11 | 99 | prod1,prod2 |
| ad2 | 6 | 15 | prod2,prod3,prod4 |
But I want this(there is a difference in the product_sale column)
| ad_name | clicks | product_sale | products |
| ------- | ------ | ------------ | ----------------- |
| ad1 | 11 | 55 | prod1,prod2 |
| ad2 | 6 | 15 | prod2,prod3,prod4 |
54 because it counts only rows with id: 1,3,4 from products_insight because in these days ad with id 1 was active. (active means that there is a row in ads_insight table.
In the link see my SQLFIDDLE and see b
CREATE TABLE Projects
(`p_id` int, `project_title` varchar(9), `l_id` int);
INSERT INTO Projects
(`p_id`, `project_title`, `l_id`)
VALUES
(1, 'A', 6),
(2, 'B', 6),
(3, 'C', 7),
(4, 'D', 8),
(5, 'E', 9),
(6, 'F', 10);
CREATE TABLE Locations
(`l_id` int, `title` varchar(9), `parent_id` int );
INSERT INTO Locations
(`l_id`, `title`, `parent_id`)
VALUES
(1, 'Country', 0),
(2, 'District1', 1),
(3, 'District2', 1),
(4, 'District3', 1),
(5, 'District4', 1),
(6, 'Loc 5', 2),
(7, 'Loc 6', 3),
(8, 'Loc 7', 3),
(9, 'Loc 8', 4),
(10, 'Loc 9', 4),
(11, 'Loc 10', 4),
(12, 'Loc 11', 5);
I would like to achieve this:
+------+-----------+-------------+
| L_ID | Title | count P_ID |
+------+-----------+-------------+
| 2 | District1 | 2 |
| 3 | District2 | 2 |
| 4 | District3 | 2 |
| 5 | District4 | 0 |
+----+------------+------+-------+
I have tried with INNER JOIN, LEFT OUTER JOIN. All i can achieve is like below and doesnt help me:
+------+-----------+----------------------+
| L_ID | Title | parent_id | counted |
+------+-----------+------------+---------+
| 6 | Loc 5 | 2 | 2 |
| 7 | Loc 6 | 3 | 2 |
| 9 | Loc 8 | 4 | 2 |
+---- -+-----------+------------+---------+
Locations table is a nested one, if this matters. I need to count projects that are in each District and also to get District name.
I tried:
SELECT l.*, COUNT(p.l_id) AS thecounted
FROM locations l
INNER JOIN projects p ON p.l_id = l.l_id
GROUP BY l.parent_id
and
SELECT l.*, COUNT(p.l_id) AS thecounted
FROM locations l
LEFT OUTER JOIN projects p on l.l_id = p.l_id
GROUP BY l.parent_id
Consider two joins:
select d.l_id, d.title, count(p.l_id) count_p_id
from locations d
left join locations l on l.parent_id = d.l_id
left join projects p on p.l_id = l.l_id
where d.parent_id = 0
group by d.l_id, d.title
The query starts from the list of districts (d), whose parent is 0. Then, it goes down one level to the locations (l), and looks up the corresponding projects (p). The final step is aggregation.
The solution of GMB returns this 1 row
l_id title count_p_id
1 Country 0
using this script version
select d.l_id, d.title, count(p.l_id) count_p_id
from locations d
left join locations l on l.parent_id = d.l_id
left join projects p on p.l_id = l.l_id
where d.parent_id = 0
group by d.l_id, d.title
We get the desired result with the slightly corrected condition
where d.parent_id = 1
Result:
l_id title count_p_id
2 District1 2
3 District2 2
4 District3 2
5 District4 0
Sorry for posting the answer, instead of a simple comment, which would be sufficient, but don't have enough reputation credits yet.
I have searched the web for my problem, tested some subqueries and derived table approaches with Case Statements, but didnĀ“t get the result. Perhaps you can help? Thanks.
The examples below are just an example.
# generate the table as it is
DROP TABLE IF EXISTS `IN`;
CREATE TABLE `IN`
(`Part` CHAR(1),
`Warehouse` INT(1),
`Percentage` INT(1),
`Update` INT(1));
#some values for the table
INSERT INTO `IN`
(Part, Warehouse, Percentage)
VALUES
('A' , 1, 80),
('A', 2, 100),
('A', 3, 50),
('B', 1, 100),
('B', 2, 50),
('B', 3, 100);
# generate table as it should be
DROP TABLE IF EXISTS `OUT`;
CREATE TABLE `OUT`
(`Part` CHAR(1),
`Warehouse` INT(1),
`Percentage` INT(1),
`Update` INT(1));
# values for the table
INSERT INTO `OUT`
(Part, Warehouse, Percentage, `Update`)
VALUES
('A' , 1, 80, 2),
('A', 2, 100, 2),
('A', 3, 50, 2),
('B', 1, 100, 3),
('B', 2, 50, 3),
('B', 3, 100, 3);
I would like to add the specific warehouse name in the column Update for the specific part if the percentage is 100.
The value of the warehouse should be filled to every row for the specific part.
The fill calculation of the update column should be in a specific order.
So first there should be a check if warehouse 3 has 100 and take this value. If warehouse 3 only has 50 then check warehouse 2, if it has 100.
Thank you very much!
Here's one way...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(Part CHAR(1)
,Warehouse INT NOT NULL
,Percentage TINYINT NOT NULL
);
INSERT INTO my_table
(Part, Warehouse, Percentage)
VALUES
('A' , 1, 80),
('A', 2, 100),
('A', 3, 50),
('B', 1, 100),
('B', 2, 50),
('B', 3, 100);
SELECT w1.*, COALESCE(w3.warehouse,w2.warehouse,w1.warehouse) warehouse
FROM my_table w1
LEFT
JOIN my_table w2
ON w2.part = w1.part
AND w2.warehouse = 2
AND w2.percentage = 100
LEFT
JOIN my_table w3
ON w3.part = w1.part
AND w3.warehouse = 3
AND w3.percentage = 100;
+------+-----------+------------+-----------+
| Part | Warehouse | Percentage | warehouse |
+------+-----------+------------+-----------+
| A | 1 | 80 | 2 |
| A | 2 | 100 | 2 |
| A | 3 | 50 | 2 |
| B | 1 | 100 | 3 |
| B | 2 | 50 | 3 |
| B | 3 | 100 | 3 |
+------+-----------+------------+-----------+
With the table and data below I am trying to get the highest effective_from values that are less than the current timestamp, per unique brand/model combination - effectively the current price per item.
CREATE TABLE things
(`id` int, `brand` varchar(1), `model` varchar(5), `effective_from` int, `price` int);
INSERT INTO things
(`id`, `brand`, `model`, `effective_from`, `price`)
VALUES
(1, 'a', 'red', 1402351200, 100),
(2, 'b', 'red', 1402351200, 110),
(3, 'a', 'green', 1402391200, 120),
(4, 'b', 'blue', 1402951200, 115),
(5, 'a', 'red', 1409351200, 150),
(6, 'a', 'blue', 1902351200, 140),
(7, 'b', 'green', 1402358200, 135),
(8, 'b', 'blue', 1902358200, 155),
(9, 'b', 'red', 1902751200, 200),
(10, 'a', 'red', 1908351200, 210),
(11, 'a', 'red', 1402264800, 660);
So far I have managed to get the row I'm looking for when I add conditions for a specific brand/model combination, but don't know how to fetch the current prices for all unique row combinations.
SELECT *
FROM things
WHERE effective_from<UNIX_TIMESTAMP()
AND brand='a'
AND model='red'
ORDER BY effective_from DESC
LIMIT 1;
If the current timestamp was 1402404432 the results should be as follows:
(1, 'a', 'red', 1402351200, 100),
(3, 'a', 'green', 1402391200, 120),
(2, 'b', 'red', 1402351200, 110),
(7, 'b', 'green', 1402358200, 135),
I guess you're after this. Advise if otherwise...
SELECT x.*
FROM things x
JOIN
( SELECT brand
, model
, MAX(effective_from) max_effective_from
FROM things
WHERE effective_from <= UNIX_TIMESTAMP()
GROUP
BY brand
, model
) y
ON y.brand = x.brand
AND y.model = x.model
AND y.max_effective_from = x.effective_from;
+------+-------+-------+----------------+-------+
| id | brand | model | effective_from | price |
+------+-------+-------+----------------+-------+
| 1 | a | red | 1402351200 | 100 |
| 2 | b | red | 1402351200 | 110 |
| 3 | a | green | 1402391200 | 120 |
| 7 | b | green | 1402358200 | 135 |
+------+-------+-------+----------------+-------+
SELECT UNIX_TIMESTAMP();
+------------------+
| UNIX_TIMESTAMP() |
+------------------+
| 1402404432 |
+------------------+
I would like to generate a SQL to list to display the maximum tally count based on enumerated group of values on a monthly basis. As this would be useful for analytics based algorithm in displaying the total impressions of a particular data type.
Please check my sample table:
CREATE TABLE IF NOT EXISTS `company_attendance_tally` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`start_date` datetime NOT NULL,
`sick_type` enum('VACATION','SICK','MATERNITY') COLLATE utf8_unicode_ci NOT NULL,
`leave_count` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `start_date` (`start_date`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=32 ;
--
-- Dumping data for table `company_attendance_tally`
--
INSERT INTO `company_attendance_tally` (`id`, `start_date`, `sick_type`, `leave_count`) VALUES
(1, '2013-03-01 16:58:44', 'VACATION', 5),
(2, '2013-03-15 10:44:35', 'SICK', 43),
(3, '2013-03-21 17:03:33', 'MATERNITY', 44),
(4, '2013-03-07 23:01:30', 'MATERNITY', 10),
(5, '2013-03-22 17:07:07', 'MATERNITY', 1),
(6, '2013-03-08 19:33:04', 'VACATION', 40),
(7, '2013-03-17 12:27:00', 'MATERNITY', 15),
(8, '2013-03-03 23:26:48', 'SICK', 11),
(9, '2013-03-05 02:16:37', 'MATERNITY', 41),
(10, '2013-03-20 12:04:28', 'MATERNITY', 18),
(11, '2013-03-18 02:10:00', 'MATERNITY', 1),
(12, '2013-03-03 09:47:02', 'MATERNITY', 19),
(13, '2013-03-22 10:17:52', 'MATERNITY', 25),
(14, '2013-03-03 19:41:52', 'VACATION', 10),
(15, '2013-03-02 19:28:41', 'SICK', 39),
(16, '2013-03-01 20:45:26', 'SICK', 42),
(17, '2013-03-26 23:52:16', 'MATERNITY', 29),
(18, '2013-03-29 14:10:58', 'SICK', 44),
(19, '2013-03-27 03:11:40', 'MATERNITY', 12),
(20, '2013-03-06 18:38:28', 'MATERNITY', 30),
(21, '2013-03-07 20:49:14', 'VACATION', 27),
(22, '2013-03-13 11:38:45', 'VACATION', 14),
(23, '2013-03-02 19:13:31', 'SICK', 2),
(24, '2013-03-01 10:08:18', 'SICK', 27),
(25, '2013-03-20 01:56:38', 'VACATION', 3),
(26, '2013-03-04 21:02:05', 'SICK', 7),
(27, '2013-03-17 00:47:17', 'MATERNITY', 36),
(28, '2013-03-04 08:12:56', 'VACATION', 5),
(29, '2013-03-18 08:50:57', 'SICK', 34),
(30, '2013-03-26 02:20:58', 'VACATION', 20),
(31, '2013-03-27 10:27:00', 'SICK', 21);
http://sqlfiddle.com/#!2/bbd1e3
I would like to display a similar output below based on the above scenario:
month| day | sick_type | leave_count |
-----------------------------------------------------
3| 08 | VACATION | 40
3| 29 | SICK | 29
3| 21 | MATERNITY | 44
and so on so forth...
4| ... | MATERNITY | ..
4| ... | SICK | ..
4| ... | VACATION | ..
5| ... | MATERNITY | ..
5| ... | SICK | ..
5| ... | VACATION | ..
If I understand correctly what you want you can do following by leveraging non-standard MySQL GROUP BY extension
SELECT MONTH(start_date) month,
DAYOFMONTH(start_date) day,
sick_type,
leave_count
FROM
(
SELECT start_date, sick_type, leave_count
FROM company_attendance_tally
WHERE start_date >= '2013-01-01'
AND start_date < '2014-01-01'
ORDER BY MONTH(start_date), sick_type, leave_count DESC
) q
GROUP BY MONTH(start_date), sick_type
Note: Month values alone (without a year values) in the resultset make sense only if you limit the resultset by one year boundaries (see WHERE clause).
Output:
| MONTH | DAY | SICK_TYPE | LEAVE_COUNT |
|-------|-----|-----------|-------------|
| 3 | 8 | VACATION | 40 |
| 3 | 29 | SICK | 44 |
| 3 | 21 | MATERNITY | 44 |
Here is SQLFiddle demo
Use this:
SELECT DAY( start_date ) AS d,
MONTH( start_date ) AS mon,
sick_type,
MAX( leave_count ) AS leave_count
FROM `company_attendance_tally`
GROUP BY mon, sick_type
If you want to do it 'by-the-book', consider the following...
SELECT x.*
FROM company_attendance_tally x
JOIN
( SELECT MONTH(start_date) start_month
, sick_type
, MAX(leave_count) max_leave_count
FROM company_attendance_tally
GROUP
BY MONTH(start_date)
, sick_type
) y
ON y.start_month = MONTH(x.start_date)
AND y.sick_type = x.sick_type
AND y.max_leave_count = x.leave_count;