Honestly, I don't know how to join a table to itself to solve this problem.
I have a table that stored it's record in the format below:
I want to query the table and display it's record in this format:
This is what I have tried so far
Select f.score as first_term, s.score as second_term, t.score as term_tetm from table f left join table s left join table t using (studentid) where studentid = 001 group by subject
You can get the result by grouping on the subject name, but then you will have to use an aggregate function. Here is an example:
CREATE TABLE #StudentGrades
(
[SUBJECT] VARCHAR(50),
[STUDENT_ID] VARCHAR(3),
[SCORE] INT,
[TERM] VARCHAR(50)
)
INSERT INTO #StudentGrades ([SUBJECT], [STUDENT_ID],[SCORE],[TERM])
VALUES ('English', '001', 50, '1st_Term'),
('Mathematics', '001', 40, '1st_Term'),
('French', '001', 60, '1st_Term'),
('English', '001', 60, '2nd_Term'),
('Mathematics', '001', 50, '2nd_Term'),
('French', '001', 50, '2nd_Term'),
('Computer', '001', 70, '2nd_Term'),
('English', '001', 65, '3rd_Term'),
('Mathematics', '001', 60, '3rd_Term'),
('French', '001', 70, '3rd_Term'),
('Computer', '001', 80, '3rd_Term')
SELECT [SUBJECT],
MAX(CASE WHEN [TERM] = '1st_Term' THEN [SCORE] END) AS '1ST_TERM',
MAX(CASE WHEN [TERM] = '2nd_Term' THEN [SCORE] END) AS '2ND_TERM',
MAX(CASE WHEN [TERM] = '3rd_Term' THEN [SCORE] END) AS '3RD_TERM'
FROM #StudentGrades
GROUP BY [SUBJECT]
ORDER BY [SUBJECT]
This is a simple solution but it works. Selecting student, subject and then sub-select for each of the terms. Finally, we DISTINCT it because there will be repetitions due to same subject on more than 1 term.
SELECT
DISTINCT
student_id,
`subject`,
(SELECT score FROM test AS t2 WHERE t2.student_id = t1.student_id AND t1.subject=t2.subject AND t2.term=1) AS term1,
(SELECT score FROM test AS t2 WHERE t2.student_id = t1.student_id AND t1.subject=t2.subject AND t2.term=2) AS term2,
(SELECT score FROM test AS t2 WHERE t2.student_id = t1.student_id AND t1.subject=t2.subject AND t2.term=3) AS term3
FROM
test AS t1
I am currently working on a booking system . I'm currently encountering a problem in finding out if an apartment is fully booked. In my database i have a table holding all the apartments and their details. I am trying to get the dates that all apartments for example with 4 bedrooms that are booked. I am running the following sql to return the booked dates of all 4 bedroom apartments.
SELECT *
FROM `apartment_booking` AS ab
JOIN apartment AS a ON ( a.id = apartmentId )
JOIN booking AS b ON ( b.id = bookingId )
WHERE bedrooms = '4'
ORDER BY checkIn
The return of the sql is
id CheckIn checkOut userId
74 2014-04-15 2014-04-22 1
75 2014-04-15 2014-04-22 1
102 2014-06-03 2014-07-07 1
71 2014-06-16 2014-06-23 1
114 2014-07-19 2014-08-02 1
121 2014-07-20 2014-08-02 1
57 2014-07-22 2014-08-05 1
122 2014-07-28 2014-08-02 1
117 2014-08-03 2014-08-10 1
As i have 4 apartments in the system with four bedrooms i would like to get the dates that all four bedrooms are booked.
Example with the output got the dates 2014-07-28 till 2014-08-02 are fully booked as in that date range there are in total four bookings.
Database:
CREATE TABLE `apartment` (
`id` int(11) NOT NULL auto_increment,
`code` varchar(4) NOT NULL,
`bedrooms` int(11) NOT NULL,
`description` varchar(500) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=26 ;
--
-- Dumping data for table `apartment`
--
INSERT INTO `apartment` (`id`, `code`, `bedrooms`, `description`) VALUES
(1, '1c', 3, ''),
(4, '4d', 4, NULL),
(5, '5b', 2, NULL),
(10, '10c', 3, NULL),
(11, '11b', 2, NULL),
(12, '12d', 4, NULL),
(13, '13c', 3, NULL),
(14, '14a', 1, 'Yo'),
(15, '15b', 2, NULL),
(16, '16b', 2, NULL),
(17, '17d', 4, NULL),
(22, '22d', 4, NULL),
CREATE TABLE `apartment_booking` (
`id` int(11) NOT NULL auto_increment,
`apartmentId` int(11) NOT NULL,
`bookingId` int(11) NOT NULL,
`ref` varchar(50) NOT NULL,
`pax` int(11) NOT NULL default '1',
`remarks` varchar(500) default NULL,
`guestFullName` varchar(30) default NULL,
`guestCountry` varchar(2) default NULL,
`guestFlightDetails` varchar(200) default NULL,
PRIMARY KEY (`id`),
KEY `apartmentId` (`apartmentId`),
KEY `bookingId` (`bookingId`),
KEY `ref` (`ref`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=179 ;
--
-- Dumping data for table `apartment_booking`
--
INSERT INTO `apartment_booking` (`id`, `apartmentId`, `bookingId`, `ref`, `pax`, `remarks`, `guestFullName`, `guestCountry`, `guestFlightDetails`) VALUES
(164, 1, 140, 'Hotelbeds', 5, '', 'Andrew Robertson', 'MT', '')
(165, 21, 141, 'Hotelbeds', 6, '', 'Pipitone', 'MT', ''),
(166, 5, 142, 'maltaholidaylets', 2, '', 'holly turpin', 'MT', ''),
(167, 12, 143, 'direct003', 4, '', 'Bernard Walch', 'MT', ''),
(168, 17, 144, 'meetingpoint', 4, '', 'Edvin Modigh', 'MT', ''),
(169, 23, 145, 'direct', 3, '', 'Andrea bacchetti', 'MT', ''),
(172, 25, 148, 'direct', 5, '', 'Wimold Peters', 'MT', ''),
(173, 20, 149, '7228110687', 4, '', 'Ms. Benedetta Tombari', 'MT', ''),
(174, 23, 149, '7228110687 meetingpoint', 2, '', 'Ms. Milena Moretti', 'MT', ''),
(175, 25, 150, 'meetingpoint', 6, '', 'N Burdett', 'MT', ''),
(176, 8, 151, 'Hotelbeds', 2, '', 'tito titti', 'MT', ''),
(177, 1, 152, 'meetingpoint', 3, '', 'Stephen Mckenna', 'MT', ''),
(178, 16, 153, 'mhcs', 4, '', 'Wojclech Blaszak', 'MT', '');
-- --------------------------------------------------------
--
-- Table structure for table `booking`
--
CREATE TABLE `booking` (
`id` int(11) NOT NULL auto_increment,
`reference` varchar(20) NOT NULL,
`dateTime` datetime NOT NULL,
`checkIn` date NOT NULL,
`checkOut` date NOT NULL,
`userId` int(11) default NULL,
PRIMARY KEY (`id`),
KEY `agent` (`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=154 ;
--
-- Dumping data for table `booking`
--
INSERT INTO `booking` (`id`, `reference`, `dateTime`, `checkIn`, `checkOut`, `userId`) VALUES
(136, 'euroresort booking.b', '2014-07-02 09:30:08', '2014-08-04', '2014-08-11', 1),
(137, '7014505534', '2014-07-02 09:32:05', '2014-07-19', '2014-07-24', 1),
(138, 'BR4277518', '2014-07-02 09:45:02', '2014-08-09', '2014-08-16', 1),
(139, '100206154', '2014-07-02 10:11:45', '2014-07-27', '2014-08-03', 1),
(140, '120-135249-95', '2014-07-02 10:13:14', '2014-07-02', '2014-07-03', 1),
(141, '120-135181-94', '2014-07-02 10:14:31', '2014-08-10', '2014-08-17', 1),
(142, '000548MHL', '2014-07-02 12:38:54', '2014-08-25', '2014-09-01', 1),
(143, 'direct003', '2014-07-02 15:48:04', '2014-08-11', '2014-08-22', 1),
(144, 'SH3049361', '2014-07-02 15:52:18', '2014-08-05', '2014-08-14', 1),
(145, 'direct009', '2014-07-03 08:27:56', '2014-07-19', '2014-07-26', 1),
(148, 'direct010', '2014-07-04 08:12:13', '2014-07-08', '2014-07-22', 1),
(149, '7228110687', '2014-07-04 13:28:16', '2014-08-10', '2014-08-16', 1),
(150, '7308310623', '2014-07-07 08:39:04', '2014-08-11', '2014-08-20', 1),
(151, '120-135677-92', '2014-07-07 08:43:06', '2014-08-22', '2014-08-29', 1),
(152, '100209964', '2014-07-07 10:59:16', '2014-08-05', '2014-08-12', 1),
(153, 'mhcs', '2014-07-07 13:07:22', '2014-08-08', '2014-08-16', 1);
It gets a bit complicated.
The following query generates a range of numbers from 0 to 999, and adds each number as a number of days to the checkIn date for each booking, where the resulting date is less than or equal to the checkOut date for bookings for apartments with 4 rooms. This should give one row per apartment per day booked.
The number of booking ids for each date is then counted, and compared with the number of apartments with 4 bedrooms (from a sub query). The HAVING clause then discards all rows for dates where the number of aparments booked is not the same as the number of apartments with 4 rooms.
SELECT aBookedDate, sub2.apartment_cnt, COUNT(id) AS all_booking_cnt
FROM
(
SELECT booking.id, DATE_ADD(booking.checkIn, INTERVAL iCnt DAY) AS aBookedDate
FROM
(
SELECT units.i + tens.i * 10 + hundreds.i * 100 AS iCnt
FROM (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)units
CROSS JOIN (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)tens
CROSS JOIN (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)hundreds
) sub0
CROSS JOIN booking
INNER JOIN apartment_booking ON booking.id = apartment_booking.bookingId
INNER JOIN apartment ON apartment.id = apartment_booking.apartmentId
WHERE DATE_ADD(booking.checkIn, INTERVAL iCnt DAY) <= booking.checkOut
AND apartment.bedrooms = 4
) sub1
CROSS JOIN
(
SELECT COUNT(*) AS apartment_cnt
FROM apartment
WHERE bedrooms = 4
) sub2
GROUP BY aBookedDate
HAVING all_booking_cnt = sub2.apartment_cnt
SQL fiddle for it:-
http://www.sqlfiddle.com/#!2/6edbe/5
You need left outer join, so you also show the apartments that are not booked.
SELECT *
FROM `apartment_booking` AS ab
JOIN apartment AS a ON ( a.id = apartmentId )
JOIN booking AS b ON ( b.id = bookingId )
WHERE bedrooms = '4' and userId is null
ORDER BY checkIn
Ones that have null user id will be empty (aka non-booked), since there is no booking connected to that apartment. You didn't say enough about the structure so I take it you delete the bookings rather than keeping history. If you keep all historical entries you need to check the date with today's date instead.
SELECT *
FROM `apartment_booking` AS ab
JOIN apartment AS a ON ( a.id = apartmentId )
LEFT OUTER JOIN booking AS b ON ( b.id = bookingId )
WHERE bedrooms = '4' and checkOut > NOW()
ORDER BY checkIn
EDIT:
It should look something like, I'll try to prepare a fiddle with that later:
SELECT
(COUNT(
SELECT *
FROM `apartment_booking` AS ab
JOIN apartment AS a ON ( a.id = apartmentId )
LEFT OUTER JOIN booking AS b ON ( b.id = bookingId )
WHERE bedrooms = '4' and checkIn <= <<<SOMEDATEHERE>>> and checkOut >= <<<<SOMEOTHERDATEHERE>>>>>
) >= 4);
Trying to get a simple SUM and COUNT from a table that takes a couple of joins and some math. I can't get it right.
I have 4 tables:
USERS
user_id, name
1, user1
2, user2
3, user3
4, user4
RESULTS
user_id, plus, minus
1, 1, 0
1, 1, 0
1, 1, 0
3, 0, 1
3, 1, 0
3, 1, 0
3, 1, 0
NOTES
user_id, note
1, lorem ipsum
3, abc
1, qwerty
3, qwerty
MESSAGES
user_id, message
1, lorem ipsum
3, abc
1, qwerty
3, qwerty
3, qwerty
3, qwerty
3, qwerty
I would like to sum all the result of subtracting plus from the minus, amount of notes and amount of messages of users.
My query:
SELECT u.`user_id`, SUM(w.`plus`-w.`minus`), COUNT(g.`user_id`), COUNT(m.`user_id`)
FROM `users` u
LEFT JOIN `results` w ON u.`user_id` = w.`user_id`
LEFT JOIN `notes` g ON u.`user_id` = g.`user_id`
LEFT JOIN `messages` m ON u.`user_id` = m.`user_id`
GROUP BY 1
Expected result should looks like:
user_id: sum(plus-minus) amount of notes, amount of messages
1: 3, 2, 2
3: 2, 2, 5
unfortunatelly query returns:
user_id: sum(plus-minus) amount of notes, amount of messages
1: 12, 12, 12
3: 20, 40, 40
Any help is greatly appreciated.
You should manually count the records in a subquery for every user_id so you will get correct value.
SELECT u.user_ID, u.Name,
COALESCE(r.totalResult, 0) totalResult,
COALESCE(n.totalNotes, 0) totalNotes,
COALESCE(m.totalMessages, 0) totalMessages
FROM users u
LEFT JOIN
(
SELECT user_ID, SUM(plus - minus) totalResult
FROM Results
GROUP BY user_ID
) r ON u.user_ID = r.user_ID
LEFT JOIN
(
SELECT user_ID, COUNT(*) totalNotes
FROM Notes
GROUP BY user_ID
) n ON u.user_ID = n.user_ID
LEFT JOIN
(
SELECT user_ID, COUNT(*) totalMessages
FROM Messages
GROUP BY user_ID
) m ON u.user_ID = m.user_ID
But if you have set an auto_incremented column in every table, the subquery isn't needed since you can distinctly count from it.
I am trying to manage seasonal prices for hotel rooms.
The only way that I can think of doing it would be to use:
A = Room Rate
B = Service Charge for room
Imagine that the table has a roomId column which is omited from below.
| DayDate |EndDate | A | B
-----------------------------------------------
| 2010/07/1 |2010/07/2 | 200 | 40
| 2010/07/3 |2010/07/4 | 150 | 40
| 2010/07/5 |2010/07/5 | 150 | 50
| 2010/07/6 |2010/07/7 | 200 | 50
| 2010/07/8 |2010/07/9 | 100 | 60
etc.. (table taken from another question).
The problem is: I don't want my seasons to be year specific.
Seasons for rooms shouldn't change year on year. I don't want my users to have to enter the seasonal information several times.
I am also going to have thousands of rooms, so I don't know a way to make this easily manageable.
I'm using mysql and php.
Start with a season table that defines the date ranges for the seasons. It should have a primary key field, say season_id. Then have another table to store room, price and season_id. The season_id is a foreign key to the season table.
Create Table Prices
(
MonthStart int not null
, DayStart int not null
, MonthEnd int not null
, DayEnd int not null
, A int not null
, B int not null
)
Insert Prices( MonthStart, DayStart, MonthEnd, DayEnd, A, B )
Select 7, 1, 7, 2, 200, 40
Union All Select 7, 3, 7, 4, 150, 40
Union All Select 7, 5, 7, 5, 150, 50
Union All Select 7, 6, 7, 7, 200, 50
Union All Select 7, 8, 7, 9, 100, 60
It should be noted that this approach presumes that the boundaries of the seasons are specific to the month and day regardless of year or circumstance. In addition, you'll have to decide how to handle leap year. Another approach which might be simpler is to simply enumerate every day of the year:
Create Table Prices
(
MonthStart int not null
, DayStart int not null
, A int not null
, B int not null
, Constraint PK_Prices Primary Key ( MonthStart, DayStart )
)
Insert Prices( MonthStart, DayStart, A, B )
Select 7, 1, 200, 40
Union All Select 7, 2, 200, 40
Union All Select 7, 3, 150, 40
Union All Select 7, 4, 150, 40
Union All Select 7, 5, 150, 50
Union All Select 7, 6, 200, 50
Union All Select 7, 7, 200, 50
Union All Select 7, 8, 100, 60
Union All Select 7, 9, 100, 60