Related
The system is a hotel management software with multiple hotels attached to it. The schema is as follows:
CREATE TABLE `ms_property` (
`id` int(10) NOT NULL,
`name` varchar(254) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `ms_property` (`id`, `name`) VALUES(1, 'Black Forest');
CREATE TABLE `ms_property_room` ( `id` int(10) NOT NULL, `property_id` int(10) NOT NULL,
`room_name` varchar(254) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `ms_property_room` (`id`, `property_id`, `room_name`) VALUES (1, 1, 'Standard Room'),
(2, 1, 'AC Room');
CREATE TABLE `ms_tariff_type` (
`tt_id` bigint(20) NOT NULL,
`tt_tariff_name` text
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `ms_tariff_type` (`tt_id`,`tt_tariff_name`) VALUES
(1, 'Season Rates'),
(2, 'Contracted Rates');
CREATE TABLE `room_tariff` (
`id` bigint(20) NOT NULL ,
`room_id` bigint(20) ,
`tariff_type_id` bigint(20) ,
`tariff_from` date,
`tariff_to` date,
`single_rate` int(11),
`default_rate` int(11)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `room_tariff` (`id`, `room_id`,`tariff_type_id`,`tariff_from`, `tariff_to`, `single_rate`, `default_rate`) VALUES
(1, 1, 1, '2019-01-01', '2019-01-20',1000,2000),
(2, 1, 2, '2019-02-06', '2019-02-12',5000,10000),
(3, 2, 1, '2019-03-05', '2019-04-10',8000,7000);
CREATE TABLE `tariff_hike_day` (
`id` bigint(20) NOT NULL,
`room_id` bigint(20) ,
`tariff_type_id` bigint(20) ,
`hd_tariff_from` date,
`hd_tariff_to` date,
`hd_single_rate` int(11),
`hd_default_rate` int(11),
`thd_sunday` smallint(6) COMMENT 'Is rate applicable on Sunday 1=>yes 0=>no',
`thd_monday` smallint(6) COMMENT 'Is rate applicable on Monday 1=>yes 0=>no',
`thd_thuesday` smallint(6) COMMENT 'Is rate applicable on Tuesday 1=>yes 0=>no',
`thd_wednesday` smallint(6) COMMENT 'Is rate applicable on Wednesday 1=>yes 0=>no',
`thd_thursday` smallint(6) COMMENT 'Is rate applicable on Thursday 1=>yes 0=>no',
`thd_friday` smallint(6) COMMENT 'Is rate applicable on Friday 1=>yes 0=>no',
`thd_saturday` smallint(6) COMMENT 'Is rate applicable on Saturday 1=>yes 0=>no'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `tariff_hike_day` (`id`, `room_id`, `tariff_type_id`,`hd_tariff_from`, `hd_tariff_to`, `hd_single_rate`, `hd_default_rate`, `thd_sunday`, `thd_monday`, `thd_thuesday`, `thd_wednesday`, `thd_thursday`, `thd_friday`, `thd_saturday`) VALUES
(1, 1, 1, '2019-01-05', '2019-01-10',100,200, 1, 1, 1, 1, 1, 1, 1),
(1, 2, 1, '2019-03-09', '2019-03-25',400,600, 1, 0, 0, 1, 0, 0, 0);
The scenario is to display the room rates applicable to hotels based on rate info provided in two tables. Normally a room will have different types of rate like "Contracted Rates", "Seasonal Rates" etc and in each type, Hotel Administrative Team will provide the applicable rates and the date range in which the rates are applicable.
The problem arises when the Hotel Administrative Team wants to specify additional hikes which are applicable on certain days. This information is stored in tariff_hike_day table where the Hotel Administrative Team can specify the date range and the days (sunday, monday etc) on which the hike is to be applied on base rate.
When the full entry is completed, the system is expected to display the result as follows:
+-------+---------------+---------------+------------------+------------+------------+-------------+--------------+
| Sl No | Property Name | Room | Tariff Type | Date From | Date To | Single Rate | Default Rate |
+-------+---------------+---------------+------------------+------------+------------+-------------+--------------+
| 1 | Black Forest | Standard Room | Season Rates | 2019-01-01 | 2019-01-04 | 1000 | 2000 |
| 2 | Black Forest | Standard Room | Season Rates | 2019-01-05 | 2019-01-10 | 1100 | 2200 |
| 3 | Black Forest | Standard Room | Season Rates | 2019-01-11 | 2019-01-20 | 1000 | 2000 |
| 4 | Black Forest | Standard Room | Contracted Rates | 2019-02-06 | 2019-02-12 | 5000 | 10000 |
| 5 | Black Forest | AC Room | Season Rates | 2019-03-05 | 2019-03-09 | 8000 | 7000 |
| 6 | Black Forest | AC Room | Season Rates | 2019-03-10 | 2019-03-10 | 8400 | 8600 |
| 7 | Black Forest | AC Room | Season Rates | 2019-03-11 | 2019-03-12 | 8000 | 7000 |
| 8 | Black Forest | AC Room | Season Rates | 2019-03-13 | 2019-03-13 | 8400 | 8600 |
| 9 | Black Forest | AC Room | Season Rates | 2019-03-14 | 2019-03-16 | 8000 | 7000 |
| 10 | Black Forest | AC Room | Season Rates | 2019-03-17 | 2019-03-17 | 8400 | 8600 |
| 11 | Black Forest | AC Room | Season Rates | 2019-03-18 | 2019-03-19 | 8000 | 7000 |
| 12 | Black Forest | AC Room | Season Rates | 2019-03-20 | 2019-03-20 | 8400 | 8600 |
| 13 | Black Forest | AC Room | Season Rates | 2019-03-21 | 2019-03-23 | 8000 | 7000 |
| 14 | Black Forest | AC Room | Season Rates | 2019-03-24 | 2019-03-24 | 8400 | 8600 |
| 15 | Black Forest | AC Room | Season Rates | 2019-03-25 | 2019-04-10 | 8000 | 7000 |
+-------+---------------+---------------+------------------+------------+------------+-------------+--------------+
Any help would be appreciated.
I know bit late to answer but hope it would help you.
First of all you need to make sure that there is no overlapped dates for same room with same tariff on both tables 'room_tariff' and 'tariff_hike_day'
To find it you can use the queries given below.
Finding Duplicate Dates(Overlapped dates) in room_tariff Table
SELECT
a.*
FROM
`room_tariff` AS a
INNER JOIN `room_tariff` AS b
ON a.`id` != b.`id`
AND a.`room_id` = b.`room_id`
AND a.`tariff_type_id` = b.`tariff_type_id`
AND NOT (
(
a.`tariff_from` > b.`tariff_from`
AND a.`tariff_from` > b.`tariff_to`
)
OR (
a.`tariff_to` < b.`tariff_from`
AND a.`tariff_to` < b.`tariff_to`
)
)
GROUP BY a.`room_id`,
a.`tariff_type_id`,
a.`tariff_from`,
a.`tariff_to`
ORDER BY a.`room_id` ASC,
a.`tariff_type_id` ASC,
a.`tariff_from` ASC ;
Finding Duplicate Dates(Overlapped dates) in tariff_hike_day Table
SELECT
a.*
FROM
`tariff_hike_day` AS a
INNER JOIN `tariff_hike_day` AS b
ON a.`id` != b.`id`
AND a.`room_id` = b.`room_id`
AND a.`tariff_type_id` = b.`tariff_type_id`
AND NOT (
(
a.`hd_tariff_from` > b.`hd_tariff_from`
AND a.`hd_tariff_from` > b.`hd_tariff_to`
)
OR (
a.`hd_tariff_to` < b.`hd_tariff_from`
AND a.`hd_tariff_to` < b.`hd_tariff_to`
)
)
GROUP BY a.`room_id`,
a.`tariff_type_id`,
a.`hd_tariff_from`,
a.`hd_tariff_to`
ORDER BY a.`room_id` ASC,
a.`tariff_type_id` ASC,
a.`hd_tariff_from` ASC ;
Both queries should return 'ZERO' rows to avoid over lapping. Here i joined same table and checking overlapped dates for same room with same tariff.
This link will help you get more explanation
To get result as you expected, We can do with the help of Stored Procedure as follows.
DELIMITER $$
DROP PROCEDURE IF EXISTS `testprocedure`$$
CREATE PROCEDURE `testprocedure`()
BEGIN
DECLARE my_id,
my_room_id,
my_tariff_type_id,
my_hd_id BIGINT ;
DECLARE my_single_rate,
my_default_rate,
my_hd_single_rate,
my_hd_default_rate INT ;
DECLARE my_tariff_from,
my_tariff_to,
my_hd_tariff_from,
my_hd_tariff_to,
currentdate,
startdate,
stopdate DATE ;
DECLARE my_thd_sunday,
my_thd_monday,
my_thd_tuesday,
my_thd_wednesday,
my_thd_thursday,
my_thd_friday,
my_thd_saturday SMALLINT ;
DECLARE cur_done INTEGER DEFAULT 0 ;
DECLARE `should_rollback` BOOL DEFAULT FALSE;
DECLARE cur1 CURSOR FOR
SELECT
a1.*,
a2.id,
hd_tariff_from,
hd_tariff_to,
hd_single_rate,
hd_default_rate,
thd_sunday,
thd_monday,
thd_thuesday,
thd_wednesday,
thd_thursday,
thd_friday,
thd_saturday
FROM
`room_tariff` AS a1
LEFT JOIN `tariff_hike_day` a2
ON a1.`room_id` = a2.`room_id`
AND a1.`tariff_type_id` = a2.`tariff_type_id`
AND a2.`hd_tariff_from` != '0000-00-00'
AND NOT (
a1.`tariff_from` > a2.`hd_tariff_to`
OR a1.`tariff_to` < a2.`hd_tariff_from`
)
WHERE a1.tariff_from != '0000-00-00'
AND a1.`tariff_from` <= a1.`tariff_to`
ORDER BY a1.`room_id` ASC,
a1.`tariff_type_id` ASC,
a1.`tariff_from` ASC,
a2.`hd_tariff_from` ASC ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET cur_done = 1 ;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET `should_rollback` = TRUE;
START TRANSACTION;
CREATE TABLE IF NOT EXISTS `room_rate_temp` (
`id` INT (11) UNSIGNED NOT NULL AUTO_INCREMENT,
`room_id` BIGINT (20) NOT NULL,
`tariff_type_id` BIGINT (20) NOT NULL,
`tariff_from` DATE NOT NULL,
`tariff_to` DATE NOT NULL,
`single_rate` INT (11) NOT NULL,
`default_rate` INT (11) NOT NULL,
`resultset_id` INT (11) UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8 ;
SET #last_res_id := 0 ;
TRUNCATE TABLE room_rate_temp ;
OPEN cur1 ;
loop_matched_tables :
LOOP
FETCH cur1 INTO my_id,
my_room_id,
my_tariff_type_id,
my_tariff_from,
my_tariff_to,
my_single_rate,
my_default_rate,
my_hd_id,
my_hd_tariff_from,
my_hd_tariff_to,
my_hd_single_rate,
my_hd_default_rate,
my_thd_sunday,
my_thd_monday,
my_thd_tuesday,
my_thd_wednesday,
my_thd_thursday,
my_thd_friday,
my_thd_saturday ;
IF cur_done = 1 THEN
CLOSE cur1 ;
LEAVE loop_matched_tables ;
END IF ;
IF my_tariff_from <= my_tariff_to THEN
IF #last_res_id = my_id THEN
SELECT id,tariff_from FROM `room_rate_temp` WHERE `resultset_id` = my_id ORDER BY id DESC LIMIT 1 INTO #lastid,#last_tariff_from ;
SET my_tariff_from := #last_tariff_from ;
DELETE FROM room_rate_temp WHERE id = #lastid ;
END IF ;
IF my_hd_id IS NULL THEN
INSERT INTO room_rate_temp
VALUES
(
NULL,
my_room_id,
my_tariff_type_id,
my_tariff_from,
my_tariff_to,
my_single_rate,
my_default_rate,
my_id
) ;
ELSE
IF ( my_hd_tariff_from <= my_hd_tariff_to ) THEN
SET startdate := my_tariff_from ;
SET currentdate := my_tariff_from ;
SET stopdate := my_tariff_to ;
SET #insflag := 1 ;
SET #last_insid := #last_hike_flag := #hiketablecovered := #splitonce := 0 ;
WHILE
currentdate <= stopdate DO
SET #my_repeat_col_name := DAYNAME(currentdate) ;
SET #hd_single_rate := my_single_rate ;
SET #hd_default_rate := my_default_rate ;
SELECT
CASE
#my_repeat_col_name
WHEN 'Sunday'
THEN my_thd_sunday
WHEN 'Monday'
THEN my_thd_monday
WHEN 'Tuesday'
THEN my_thd_tuesday
WHEN 'Wednesday'
THEN my_thd_wednesday
WHEN 'Thursday'
THEN my_thd_thursday
WHEN 'Friday'
THEN my_thd_friday
WHEN 'Saturday'
THEN my_thd_saturday
ELSE NULL
END AS mydate INTO #hikeapplicable ;
IF ( currentdate BETWEEN my_hd_tariff_from AND my_hd_tariff_to ) THEN
IF ( #last_hike_flag != #hikeapplicable ) THEN
SET #insflag := 1 ;
SET #last_hike_flag := #hikeapplicable ;
SET #splitonce := 1 ;
IF ( #hikeapplicable = 1 ) THEN
SET #hd_single_rate := my_single_rate + my_hd_single_rate ;
SET #hd_default_rate := my_default_rate + my_hd_default_rate ;
END IF ;
END IF ;
SET #hiketablecovered := 1;
ELSEIF ( (currentdate > my_hd_tariff_to) AND ( #hiketablecovered = 1 ) AND (#splitonce = 1) ) THEN
IF(#last_hike_flag = 1) THEN
SET #insflag := 1;
END IF ;
SET #hiketablecovered := #splitonce := 0 ;
END IF ;
IF (#insflag = 1) THEN
INSERT INTO room_rate_temp VALUES ( NULL, my_room_id, my_tariff_type_id, currentdate, currentdate, #hd_single_rate, #hd_default_rate, my_id );
SET #last_insid := LAST_INSERT_ID() ;
SET #insflag := 0 ;
ELSE
UPDATE room_rate_temp SET tariff_to = currentdate WHERE id = #last_insid;
END IF ;
SET currentdate = ADDDATE(currentdate, INTERVAL 1 DAY) ;
END WHILE ;
END IF ;
END IF ;
SET #last_res_id := my_id;
END IF ;
END LOOP loop_matched_tables ;
SET #count:=0;
SELECT (#count:=#count+1) AS `Sl No`, d.name AS `Property Name`, c.room_name AS Room, b.tt_tariff_name AS `Tariff Type`, a.tariff_from AS `Date From`, a.tariff_to AS `Date To`, a.single_rate AS `Single Rate`, a.default_rate AS `Default Rate`
FROM room_rate_temp AS a INNER JOIN ms_tariff_type AS b ON a.tariff_type_id = b.tt_id INNER JOIN ms_property_room AS C
ON a.room_id = c.id INNER JOIN ms_property AS d ON c.property_id = d.id;
IF `should_rollback` THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
END$$
DELIMITER ;
In this procedure,
For storing the result, I created one temp table and will exist until next query so that you can fetch last result at any time.
First i joined tariff and hike table to find the matching for similar date range.
Then looping the query result and breaks rows when hike is applicable.
I'm hoping there is a simple answer to this. Competitors race over a series of 3 races. Some competitors only show up for one race. How could I show a final result for ALL competitors?
race 1
+------+--------+
| name | result |
+------+--------+
| Ali | 30 |
| Bob | 28 |
| Cal | 26 |
+------+--------+
race 2
+------+--------+
| name | result |
+------+--------+
| Ali | 32 |
| Bob | 31 |
| Dan | 24 |
+------+--------+
race 3
+------+--------+
| name | result |
+------+--------+
| Eva | 23 |
| Dan | 25 |
+------+--------+
The final result should look like this:
+------+--------+--------+--------+
| name | result | result | result |
+------+--------+--------+--------+
| Ali | 30 | 32 | |
| Bob | 28 | 31 | |
| Cal | 26 | | |
| Dan | | 24 | 25 |
| Eva | | | 23 |
+------+--------+--------+--------+
The problem I have is with ordering by name from multiple tables.
Here is the example data:
CREATE TABLE race (name varchar(20), result int);
CREATE TABLE race1 LIKE race;
INSERT INTO race1 VALUES ('Ali', '30'), ('Bob', '28'), ('Cal', '26');
CREATE TABLE race2 like race;
insert INTO race2 VALUES ('Ali', '32'), ('Bob', '31'), ('Dan', '24');
CREATE TABLE race3 LIKE race;
INSERT INTO race3 VALUES ('Eva', '23'), ('Dan', '25');
Many thanks!
Here we go !!!
select race1.name as name, race1.result, race2.result, race3.result from race1
left join race2 on race2.name = race1.name
left join race3 on race3.name = race1.name
union
select race2.name as name, race1.result, race2.result, race3.result from race2
left join race1 on race1.name = race2.name
left join race3 on race3.name = race2.name
union
select race3.name as name, race1.result, race2.result, race3.result from race3
left join race1 on race1.name = race3.name
left join race2 on race2.name = race3.name;
It is working :)
select s.name,
max(case when s.R = 'Result1' then s.result else '' end) as result1,
max(case when s.R = 'Result2' then s.result else '' end) as result2,
max(case when s.R = 'Result3' then s.result else '' end) as result3
from
(
select 'Result1' as R,r1.* from race1 r1
union all
select 'Result2' as R,r2.* from race2 r2
union all
select 'Result3' as R,r3.* from race3 r3
) s
group by s.name
result
+------+---------+---------+---------+
| name | result1 | result2 | result3 |
+------+---------+---------+---------+
| Ali | 30 | 32 | |
| Bob | 28 | 31 | |
| Cal | 26 | | |
| Dan | | 24 | 25 |
| Eva | | | 23 |
+------+---------+---------+---------+
5 rows in set (0.00 sec)
I personally would create the schema in a different way.
One table for the users, one for the races and one that connects both:
-- Create syntax for TABLE 'races'
CREATE TABLE `races` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Create syntax for TABLE 'users'
CREATE TABLE `users` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Create syntax for TABLE 'race_results'
CREATE TABLE `race_results` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`race_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`result` int(11) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Let's insert some data (should be equal to your data set).
-- Insert data
INSERT INTO users (name)values('Ali'),('Bob'),('Cal'),('Dan'), ('Eva');
INSERT INTO races (name)values('Race1'),('Race2'),('Race3');
INSERT INTO race_results (user_id, race_id, result)values(1,1,30),(2,1,30),(1,2,28),(2,2,31),(3,1,26),(4,2,24),(4,3,25),(5,3,23);
Then you could write the query like this:
-- Static version
SELECT us.name, sum(if(ra.name='Race1', result, null)) as Race1, sum(if(ra.name='Race2', result, null)) as Race2, sum(if(ra.name='Race3', result, null)) as Race3
FROM race_results as rr
LEFT JOIN users as us on us.id = rr.user_id
LEFT JOIN races as ra on ra.id = rr.race_id
GROUP BY us.id;
Which gives you the result you're looking for. (I changed the column names to make it more obvious which result belongs to which race.)
But I've to admit that this works fine for 3 races but what if you have 30 or more?
Here is a more dynamic version of the above query, which kind of creates itself ;)
-- Dynamic version
SET #sql = '';
SELECT
#sql := CONCAT(#sql,if(#sql='','',', '),temp.output)
FROM
(SELECT
CONCAT("sum(if(ra.name='", race.name, "', result, null)) as ", race.name) as output
FROM races as race
) as temp;
SET #sql = CONCAT("SELECT us.name,", #sql, " FROM race_results as rr LEFT JOIN users as us on us.id = rr.user_id LEFT JOIN races as ra on ra.id = rr.race_id GROUP BY 1;");
SELECT #sql;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Given the table:
CREATE TABLE `records` (
`id_type` varchar(50) NOT NULL,
`old_id` INT,
`new_id` INT,
) ENGINE=InnoDB;
And the data:
id_type | old_id | new_id
USER | 11 | NULL
USER | 15 | NULL
USER | 56 | NULL
USER | NULL | 500
USER | NULL | 523
USER | NULL | 800
I want to perform a query that will return:
id_type | old_id | new_id
USER | 11 | 500
USER | 15 | 523
USER | 56 | 800
Create table records_old
(
id_type varchar(20) primary key,
old_id int not null
);
Create table records_new
(
id_type varchar(20),
new_id int not null
);
insert into records_old(id_type,old_id) values ('USER1',11);
insert into records_old(id_type,old_id) values ('USER2',12);
insert into records_old(id_type,old_id) values ('USER3',13);
insert into records_new(id_type,new_id) values ('USER1',500);
insert into records_new(id_type,new_id) values ('USER2',600);
insert into records_new(id_type,new_id) values ('USER3',700);
select * from records_old;
select * from records_new;
select a.id_type,a.old_id,b.new_id from records_old a
inner join records_new b
where a.id_type=b.id_type;
SET #old_row_number = 0;
SET #new_row_number = 0;
SELECT OldData.id_type, OldData.old_id, NewData.new_id
FROM (SELECT id_type, old_id, (#old_row_number:=#old_row_number + 1) AS OldRowNumber
FROM `records`
WHERE old_id IS NOT NULL) OldData
JOIN (SELECT id_type, new_id, (#new_row_number:=#new_row_number + 1) AS NewRowNumber
FROM `records`
WHERE new_id IS NOT NULL) NewData ON NewData.NewRowNumber = OldData.OldRowNumber
Filter with id is not null and separate as two sub-queries and add a row number for each row then join will help in your case.
Working Demo
I need to sum-up the amount in 2 tables (c1, c2) linked n:1 to table a. The problem is: It would be greate if I could do it in just 1 query, because the real situation is a bit more complicated ;-) I brought it down to this testcase:
create table a (
`id` int(10) unsigned NOT NULL, KEY(id)
) ENGINE=InnoDB;
create table c1 (
`id` int(10) unsigned NOT NULL, KEY(id),
`a` int(10),
`amount` decimal(15,2) NOT NULL
) ENGINE=InnoDB;
create table c2 (
`id` int(10) unsigned NOT NULL, KEY(id),
`a` int(10),
`amount` decimal(15,2) NOT NULL
) ENGINE=InnoDB;
INSERT INTO a SET id=1;
INSERT INTO c1 SET a=1, amount = 2;
INSERT INTO c1 SET a=1, amount = 3;
INSERT INTO c2 SET a=1, amount = 1;
SELECT SUM(c1.amount), SUM(c2.amount)
FROM a
LEFT JOIN c1 ON c1.a = a.id
LEFT JOIN c2 ON c2.a = a.id
WHERE a.id = 1;
The result of course is:
+----------------+----------------+
| SUM(c1.amount) | SUM(c2.amount) |
+----------------+----------------+
| 5.00 | 2.00 |
+----------------+----------------+
because c1 is joined twice and doubles the amound in c2. But I need to get:
+----------------+----------------+
| SUM(c1.amount) | SUM(c2.amount) |
+----------------+----------------+
| 5.00 | 1.00 |
+----------------+----------------+
Any idea how to get to this?
One possible answer is:
SELECT (select SUM(c1.amount) from c1 where c1.a = a.id) as c1_amount,
(select SUM(c2.amount) from c2 where c2.a = a.id) as c2_amount
FROM a
WHERE a.id = 1;
Link to SQL Fiddle
BTW - Thanks for putting in the data and create scripts. That helped a lot.
SELECT a.*
, SUM(CASE WHEN b.source = 'c1' THEN amount END) c1_ttl
, SUM(CASE WHEN b.source = 'c2' THEN amount END) c2_ttl
FROM a
JOIN
(
SELECT *,'c1' source FROM c1 UNION SELECT *,'c2' FROM c2
) b
ON b.a = a.id;
+----+--------+--------+
| id | c1_ttl | c2_ttl |
+----+--------+--------+
| 1 | 5.00 | 1.00 |
+----+--------+--------+
Another solution.
SELECT *
FROM
(SELECT SUM(c1.amount) FROM c1 WHERE c1.a = 1) C1
INNER JOIN
(SELECT SUM(c2.amount) FROM c2 WHERE c2.a = 1) C2;
This is my table structure:
id id_parent id_origin level name
1 0 1 1 PHP
2 0 2 1 Javascript
3 0 3 1 SMARTY
4 0 4 1 HTML
5 1 1 2 Basic
6 1 1 2 Date & Math Function
8 2 2 2 DOM
9 5 1 3 Introduction
10 5 1 3 Session & Cookies
12 2 2 2 Introduction
13 4 4 2 Basic Structure
14 6 1 3 PHP Date Function
16 3 3 2 Basic Syntax
26 4 4 2 Table
I want result like below format
Myfinalstr
-----------
PHP
PHP->Basic
PHP->Basic->Introduction
PHP->Basic->Session & Cookies
PHP->Date & Match Function
PHP->Date & Match Function->PHP Date Function
Javascript
Javascript->DOM
Javascript->Introduction
SMARTY
SMARTY->Basic Syntax
HTML
HTML->Basic Structure
HTML->Table
The following isnt a complete solution but it will get you started:
Example stored procedure call
mysql> call chapter_hier(1);
+----+----------------------+-----------+----------------------+-------+
| id | category_name | id_parent | parent_category_name | depth |
+----+----------------------+-----------+----------------------+-------+
| 1 | PHP | NULL | NULL | 0 |
| 5 | Basic | 1 | PHP | 1 |
| 6 | Date & Math Function | 1 | PHP | 1 |
| 9 | Introduction | 5 | Basic | 2 |
| 10 | Session & Cookies | 5 | Basic | 2 |
| 14 | PHP Date Function | 6 | Date & Math Function | 2 |
+----+----------------------+-----------+----------------------+-------+
6 rows in set (0.00 sec)
$result = $conn->query(sprintf("call chapter_hier(%d)", 1));
Full script and test data
drop table if exists chapters;
create table chapters
(
id smallint unsigned not null primary key,
name varchar(255) not null,
id_parent smallint unsigned null,
key (id_parent)
)
engine = innodb;
insert into chapters (id, name, id_parent) values
(1,'PHP',null),
(2,'Javascript',null),
(3,'SMARTY',null),
(4,'HTML',null),
(5,'Basic',1),
(6,'Date & Math Function',1),
(8,'DOM',2),
(9,'Introduction',5),
(10,'Session & Cookies',5),
(12,'Introduction',2),
(13,'Basic Structure',4),
(14,'PHP Date Function',6),
(16,'Basic Syntax',3),
(26,'Table',4);
drop procedure if exists chapter_hier;
delimiter #
create procedure chapter_hier
(
in p_id smallint unsigned
)
begin
declare v_done tinyint unsigned default 0;
declare v_depth smallint unsigned default 0;
create temporary table hier(
id_parent smallint unsigned,
id smallint unsigned,
depth smallint unsigned default 0
)engine = memory;
insert into hier select id_parent, id, v_depth from chapters where id = p_id;
create temporary table tmp engine=memory select * from hier;
/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */
while not v_done do
if exists( select 1 from chapters c
inner join tmp on c.id_parent = tmp.id and tmp.depth = v_depth) then
insert into hier select c.id_parent, c.id, v_depth + 1 from chapters c
inner join tmp on c.id_parent = tmp.id and tmp.depth = v_depth;
set v_depth = v_depth + 1;
truncate table tmp;
insert into tmp select * from hier where depth = v_depth;
else
set v_done = 1;
end if;
end while;
select
c.id,
c.name as category_name,
p.id as id_parent,
p.name as parent_category_name,
hier.depth
from
hier
inner join chapters c on hier.id = c.id
left outer join chapters p on hier.id_parent = p.id
order by
hier.depth;
drop temporary table if exists hier;
drop temporary table if exists tmp;
end #
delimiter ;
Hope it helps :)