I have the following DB scheme for university elections:
for each department, I have the following positions:
1 CHEF (which is the candidate_position = 1)
& 6 Members (which is the candidate_position = 2)
I want to obtain the winners of the election in each department.
to obtain the winner of CHEF position in "Informatique" department, I did the following query:
SELECT doctor.firstname, doctor.lastname, votes
FROM (SELECT COUNT(*) AS votes FROM candidate_votes WHERE candidate_votes.candidate_position = 1 GROUP BY candidate_votes.candidate_id) AS votes, doctor
INNER JOIN department_candidates ON department_candidates.doctor_id = doctor.id
INNER JOIN department ON department.id = department_candidates.department_id AND department.name = 'Informatique'
INNER JOIN candidate_votes ON candidate_votes.candidate_id = doctor.id AND candidate_votes.candidate_position = 1
GROUP BY candidates_votes.candidate_id
please note I didn't use LIMIT 1 because may be there is a tie (or draw) of votes between multiple candidates
based on the results, I think that my query of selecting the winner of Chef position is right, But I want some help to know how to select the first 6 candidates of Member position ?
Data set:
--
-- Table structure for table `candidate_votes`
--
DROP TABLE IF EXISTS `candidate_votes`;
CREATE TABLE IF NOT EXISTS `candidate_votes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`candidate_id` int(11) NOT NULL,
`voter_id` int(11) NOT NULL,
`candidate_position` tinyint(1) NOT NULL COMMENT '1: chef, 2: member',
`date` date NOT NULL,
PRIMARY KEY (`id`),
KEY `fk-candidate_votes-voter_id` (`voter_id`),
KEY `fk-candidate_votes-candidate_id_idx` (`candidate_id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8;
--
-- Dumping data for table `candidate_votes`
--
INSERT INTO `candidate_votes` (`id`, `candidate_id`, `voter_id`, `candidate_position`, `date`) VALUES
(24, 2, 1, 1, '2018-05-26'),
(25, 1, 1, 2, '2018-05-26'),
(26, 6, 1, 2, '2018-05-26'),
(27, 5, 1, 2, '2018-05-26'),
(28, 7, 1, 2, '2018-05-26'),
(29, 8, 1, 2, '2018-05-26'),
(30, 9, 1, 2, '2018-05-26'),
(31, 2, 2, 1, '2018-05-16'),
(32, 3, 7, 1, '2018-05-22'),
(33, 3, 8, 1, '2018-05-22'),
(34, 4, 6, 2, '2018-05-29'),
(35, 7, 6, 2, '2018-05-29');
-- --------------------------------------------------------
--
-- Table structure for table `department`
--
DROP TABLE IF EXISTS `department`;
CREATE TABLE IF NOT EXISTS `department` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `department-name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
--
-- Dumping data for table `department`
--
INSERT INTO `department` (`id`, `name`) VALUES
(1, 'Informatique'),
(2, 'Mathematique'),
(4, 'physique');
-- --------------------------------------------------------
--
-- Table structure for table `department_candidates`
--
DROP TABLE IF EXISTS `department_candidates`;
CREATE TABLE IF NOT EXISTS `department_candidates` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`department_id` int(11) NOT NULL,
`doctor_id` int(11) NOT NULL,
`candidate_position` tinyint(1) NOT NULL COMMENT '1: chef, 2: member',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
--
-- Dumping data for table `department_candidates`
--
INSERT INTO `department_candidates` (`id`, `department_id`, `doctor_id`, `candidate_position`) VALUES
(5, 1, 3, 1),
(7, 1, 4, 2),
(8, 1, 1, 2),
(9, 1, 2, 1),
(10, 1, 6, 2),
(11, 1, 5, 2),
(12, 1, 7, 2),
(13, 1, 8, 2),
(14, 1, 9, 2);
-- --------------------------------------------------------
--
-- Table structure for table `doctor`
--
DROP TABLE IF EXISTS `doctor`;
CREATE TABLE IF NOT EXISTS `doctor` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`firstname` varchar(255) NOT NULL,
`lastname` varchar(255) NOT NULL,
`department_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
--
-- Dumping data for table `doctor`
--
INSERT INTO `doctor` (`id`, `firstname`, `lastname`, `department_id`) VALUES
(1, 'doc1_fn', 'doc1_ln', 1),
(2, 'doc2_fn', 'doc2_ln', 1),
(3, 'doc3_fn', 'doc3_ln', 1),
(4, 'doc4_fn', 'doc4_ln', 1),
(5, 'doc5_fn', 'doc5_ln', 1),
(6, 'doc6_fn', 'doc6_ln', 1),
(7, 'doc7_fn', 'doc7_ln', 1),
(8, 'doc8_fn', 'doc8_ln', 1),
(9, 'doc9_fn', 'doc9_ln', 1);
-- --------------------------------------------------------
Sqlfiddle DEMO
Consider the following:
SELECT x.*
, CASE WHEN #prev_position = candidate_position THEN CASE WHEN #prev_total = total THEN #i:=#i ELSE #i:=#i+1 END ELSE #i:=1 END i
, #prev_position := candidate_position prev_position
, #prev_total := total prev_total
FROM
(
SELECT candidate_id
, candidate_position
, COUNT(*) total
FROM candidate_votes
GROUP
BY candidate_id
, candidate_position
) x
JOIN
( SELECT #prev_position := null,#prev_total:=null,#i:=0) vars
ORDER
BY candidate_position
, total DESC;
+--------------+--------------------+-------+------+---------------+------------+
| candidate_id | candidate_position | total | i | prev_position | prev_total |
+--------------+--------------------+-------+------+---------------+------------+
| 2 | 1 | 2 | 1 | 1 | 2 |
| 3 | 1 | 2 | 1 | 1 | 2 |
| 7 | 2 | 2 | 1 | 2 | 2 |
| 8 | 2 | 1 | 2 | 2 | 1 |
| 9 | 2 | 1 | 2 | 2 | 1 |
| 1 | 2 | 1 | 2 | 2 | 1 |
| 4 | 2 | 1 | 2 | 2 | 1 |
| 5 | 2 | 1 | 2 | 2 | 1 |
| 6 | 2 | 1 | 2 | 2 | 1 |
+--------------+--------------------+-------+------+---------------+------------+
In this example, i represents rank. For position 1, we can see that two candidates tied for first place. For position 2, there was one outright winner, with all remaining candidates tying for second place.
Apparently I was trying to be too clever in my other answer, you can achieve a simple ranking table like this:
SELECT cast(dc.candidate_position AS UNSIGNED) AS position, dc.doctor_id, doc.firstname, doc.lastname, v.votes
FROM department_candidates dc
JOIN department dept ON dept.id=dc.department_id AND dept.name='Informatique'
JOIN doctor doc ON doc.id=dc.doctor_id
JOIN (SELECT candidate_position AS cp, candidate_id AS cid, count(candidate_id) AS votes
FROM candidate_votes
GROUP BY cid) v
ON v.cid=doc.id AND v.cp = dc.candidate_position
ORDER BY position, v.votes DESC
Output:
position doctor_id firstname lastname votes
1 3 doc3_fn doc3_ln 2
1 2 doc2_fn doc2_ln 2
2 7 doc7_fn doc7_ln 2
2 4 doc4_fn doc4_ln 1
2 1 doc1_fn doc1_ln 1
2 6 doc6_fn doc6_ln 1
2 5 doc5_fn doc5_ln 1
2 8 doc8_fn doc8_ln 1
2 9 doc9_fn doc9_ln 1
Demo
This query will give you the number of votes required to be a winner for a given position (note I have parameterised it with variables):
SET #position = 2;
SET #numwinners = 3;
SELECT #rank := #rank+1 AS rank, votes
FROM (SELECT COUNT(candidate_id) AS votes
FROM candidate_votes
WHERE candidate_position = #position
GROUP BY candidate_id
ORDER BY votes DESC) vr
JOIN (select #rank := 0) r
GROUP BY rank
HAVING rank = #numwinners
Output for your data with #position=2 and #numwinners=3:
rank votes
3 1
Having figured out how many votes are required to be a winner, we just need to find all candidates that have the required number of votes. Since the results are based on number of votes, ties are automatically taken care of. This query will generate that output:
SET #position = 2;
SET #numwinners = 3;
SELECT doc.firstname, doc.lastname, v.votes
FROM department_candidates dc
JOIN department dept ON dept.id=dc.department_id AND dept.name='Informatique'
JOIN doctor doc ON doc.id=dc.doctor_id
JOIN (SELECT candidate_id AS cid, count(candidate_id) AS votes
FROM candidate_votes
WHERE candidate_position = #position
GROUP BY cid) v
ON v.cid=dc.id
WHERE v.votes >= (SELECT votes
FROM (SELECT #rank := #rank+1 AS rank, votes
FROM (SELECT COUNT(candidate_id) AS votes
FROM candidate_votes
WHERE candidate_position = #position
GROUP BY candidate_id
ORDER BY votes DESC) vr
JOIN (select #rank := 0) r
GROUP BY rank
HAVING rank = #numwinners
) vt
)
ORDER BY v.votes DESC
Output for your data with #position=2 and #numwinners=3:
firstname lastname votes
doc7_fn doc7_ln 2
doc4_fn doc4_ln 1
doc1_fn doc1_ln 1
doc6_fn doc6_ln 1
doc5_fn doc5_ln 1
doc8_fn doc8_ln 1
doc9_fn doc9_ln 1
Output for your data with #position=1 and #numwinners=1:
firstname lastname votes
doc3_fn doc3_ln 2
doc2_fn doc2_ln 2
If you want to ensure the query works even if the value of #numwinners is greater than the number of candidates, change:
HAVING rank = #numwinners
to
HAVING rank = LEAST(#numwinners, (SELECT COUNT(DISTINCT candidate_id)
FROM candidate_votes
WHERE candidate_position = #position))
Demo
Related
I am having three tables bible_chapters, bible_reading_portions, user_bible_trackings, 1 chapter may have multiple bible portions and we are tracking portions in user_bible_trackings table. Below is my schema:-
bible_chapters
id chapter_name
1 Chpt1
2 Chpt2
3 Chpt3
bible_reading_portions
id bible_chapter_id portion_name
1 1 Chp1P1
2 2 Chp2P1
3 2 Chp2P2
4 2 Chp2P3
5 3 Chp3P1
user_bible_trackings
id bible_reading_portion_id user_id
1 1 1
2 2 1
3 3 1
4 4 1
5 1 1
6 2 1
7 3 1
8 4 1
9 1 1
10 2 1
So you see that above user_bible_trackings table user_id 1 have read Chpt1 3 times and Chpt2 2 times and user again started the chapter2 3rd time but its not complete yet beacuse chapt2 belongs to 3 portions,.... for the 3rd time user not read all the portions. So my expected output be like:-
user_id total_chapteres_read
1 5 // i.e means user read chpt1 3 times and chpt2 2 times so count will be 3+2=5
Can anyone help me how can i acheieve the same.
#Akina PLease check i have added the schema queries below:-
CREATE TABLE `bible_chapters` (
`id` int(11) NOT NULL,
`chapter_name` varchar(150) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `bible_chapters` (`id`, `chapter_name`) VALUES
(1, 'Chp1'),
(2, 'Chp2'),
(3, 'Chp3');
---------------------
CREATE TABLE `bible_reading_portions` (
`id` int(11) NOT NULL,
`bible_chapter_id` int(11) NOT NULL,
`portion_name` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `bible_reading_portions` (`id`, `bible_chapter_id`, `portion_name`)
VALUES
(1, 1, 'Chp1p1'),
(2, 2, 'Chp2p2'),
(3, 2, 'Chp2p2'),
(4, 2, 'Chp2p3');
-----------
CREATE TABLE `user_bible_trackings` (
`id` int(11) NOT NULL,
`bible_reading_portion_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `user_bible_trackings` (`id`, `bible_reading_portion_id`, `user_id`) VALUES
(1, 1, 1),
(2, 2, 1),
(3, 3, 1),
(4, 4, 1),
(5, 1, 1),
(6, 2, 1),
(7, 3, 1),
(8, 4, 1),
(9, 1, 1),
(10, 2, 1);
WITH
cte1 AS (
SELECT ubt.user_id,
bc.id bc_id, bc.chapter_name,
brp.id brp_id, brp.portion_name,
COUNT(*) cnt
FROM bible_chapters bc
JOIN bible_reading_portions brp ON bc.id = brp.bible_chapter_id
JOIN user_bible_trackings ubt ON brp.id = ubt.bible_reading_portion_id
GROUP BY 1,2,3,4,5
),
cte2 AS (
SELECT user_id, bc_id,
COUNT(brp_id) portions_count,
MIN(cnt) complete_readings
FROM cte1
GROUP BY 1,2
)
SELECT user_id, SUM(complete_readings) total_readings
FROM cte2
GROUP BY 1
fiddle with some comments.
The solution does not check does all portions of a chapter were read. For to take this into account you must compare portions_count (added but not used) with the same value for a chapter (obtained in separate CTE).
We are developing a ticket system and for the dashboard we want to show the tickets with it's latest status. We have two tables. The first one for the ticket itself and a second table for the individual edits.
The system is running already, but the performance for the dashboard is very bad (6 seconds for ~1300 tickets). At first we used a statemant which selected 'where timestamp = (select max(Timestamp))' for every ticket. In the second step we created a view which only includes the latest timestamp for every ticket, but we are not able to also include the correct status into this view.
So the main Problem might be, that we can't build a table in which for every ticket the lastest ins_date and also the latest status is selected.
Simplyfied database looks like:
CREATE TABLE `ticket` (
`id` int(10) NOT NULL,
`betreff` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `ticket_relation` (
`id` int(11) NOT NULL,
`ticket` int(10) NOT NULL,
`info` varchar(10000) DEFAULT NULL,
`status` int(1) NOT NULL DEFAULT '0',
`ins_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`ins_user` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `ticket` (`id`, `betreff`) VALUES
(1, 'Technische Frage'),
(2, 'Ticket 2'),
(3, 'Weitere Fragen');
INSERT INTO `ticket_relation` (`id`, `ticket`, `info`, `status`, `ins_date`, `ins_user`) VALUES
(1, 1, 'Betreff 1', 0, '2019-05-28 11:02:18', 123),
(2, 1, 'Betreff 2', 3, '2019-05-28 12:07:36', 123),
(3, 2, 'Betreff 3', 0, '2019-05-29 06:49:32', 123),
(4, 3, 'Betreff 4', 1, '2019-05-29 07:44:07', 123),
(5, 2, 'Betreff 5', 1, '2019-05-29 07:49:32', 123),
(6, 2, 'Betreff 6', 3, '2019-05-29 08:49:32', 123),
(7, 3, 'Betreff 7', 2, '2019-05-29 09:49:32', 123),
(8, 2, 'Betreff 8', 1, '2019-05-29 10:49:32', 123),
(9, 3, 'Betreff 9', 2, '2019-05-29 11:49:32', 123),
(10, 3, 'Betreff 10', 3, '2019-05-29 12:49:32', 123);
I have created a SQL Fiddle: http://sqlfiddle.com/#!9/a873b6/3
The first three Statements are attempts that won't work correct or way too slow. The last one is the key I think, but I don't understand, why this gets the status wrong.
The attempt to create the table with latest ins_date AND status for each ticket:
SELECT
ticket, status, MAX(ins_date) as max_date
FROM
ticket_relation
GROUP BY
ticket
ORDER BY
ins_date DESC;
This query gets the correct (latest) ins_date for every ticket, but not the latest status:
+--------+--------+----------------------+
| ticket | status | max_date |
+--------+--------+----------------------+
| 3 | 1 | 2019-05-29T12:49:32Z |
+--------+--------+----------------------+
| 2 | 0 | 2019-05-29T10:49:32Z |
+--------+--------+----------------------+
| 1 | 0 | 2019-05-28T12:07:36Z |
+--------+--------+----------------------+
Expected output would be this:
+--------+--------+----------------------+
| ticket | status | max_date |
+--------+--------+----------------------+
| 3 | 3 | 2019-05-29T12:49:32Z |
+--------+--------+----------------------+
| 2 | 1 | 2019-05-29T10:49:32Z |
+--------+--------+----------------------+
| 1 | 3 | 2019-05-28T12:07:36Z |
+--------+--------+----------------------+
Is there a efficient way to select the latest timestamp and status for every ticket in the tiket-table?
Other approach is to think filtering not GROUPing..
Query
SELECT
ticket_relation_1.ticket
, ticket_relation_1.status
, ticket_relation_1.ins_date
FROM
ticket_relation AS ticket_relation_1
LEFT JOIN
ticket_relation AS ticket_relation_2
ON
ticket_relation_1.ticket = ticket_relation_2.ticket
AND
ticket_relation_1.ins_date < ticket_relation_2.ins_date
WHERE
ticket_relation_2.id IS NULL
ORDER BY
ticket_relation_1.id DESC
Result
| ticket | status | ins_date |
| ------ | ------ | ------------------- |
| 3 | 3 | 2019-05-29 12:49:32 |
| 2 | 1 | 2019-05-29 10:49:32 |
| 1 | 3 | 2019-05-28 12:07:36 |
see demo
This query would require a index KEY(ticket, ins_date, id) to get max performance..
One solution would be to use a subquery to compute the latest insert date for each ticket, and then to join the results with the original table, like:
SELECT t.ticket, t.status, t.ins_date
FROM ticket_relation t
INNER JOIN (
SELECT ticket, max(ins_date) max_ins_date
FROM ticket_relation
GROUP BY ticket
) x ON t.ticket = x.ticket AND t.ins_date = x.max_ins_date
For better performance with this query, you want an index on (ticket, ins_date).
Anoter option would be to use a NOT EXISTS condition to ensure that only the latest record is selected, like:
SELECT t.ticket, t.status, t.ins_date
FROM ticket_relation t
WHERE NOT EXISTS (
SELECT 1
FROM ticket_relation t1
WHERE t1.ticket = t.ticket AND t1.ins_date > t.ins_date)
)
NB: when dealing with GROUP BY, all non-aggregated columns must appear in the GROUP BY clause. Else, you will get either an error or unprectictable results (depending on whether server option ONLY_FULL_GROUP_BY is, respectively, enabled or disabled).
If you are able to upgrade to a recent version of mysql (8.0), then window functions can be used to simplify the query and possibly increase its performance, like:
SELECT ticket, status, ins_date
FROM (
SELECT
ticket,
status,
ins_date,
row_number() over(partition by ticket order by ins_date desc) rn
FROM ticket_relation
) x WHERE rn = 1
You can try below query -
SELECT
ticket, status, ins_date as max_date
FROM ticket_relation a
where ins_date in (select max(ins_date) from ticket_relation b where a.ticket=b.ticket)
I am having trouble either getting any result or a correct result in the following problem - http://www.sqlfiddle.com/#!9/696ed2/4
Overall goal is to list all transactions of users who are linked together as 'Customers'. So if John is looking at his dashboard, he will see which books Alice (his customer) has rented (including book title), and which books were sold (he won't be able to see the title of that book).
When two multiple tables are joined to the parent table, where both depending tables have an 'active' flag set against each row, I can't seem to get only active rows.
# USERS
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`active` boolean DEFAULT NULL
);
INSERT INTO `users` (`id`, `name`, `active`) VALUES
(1, 'John', 1),
(2, 'Alice', 1),
(3, 'Jess', 1),
(4, 'Bob', 1);
# BOOKS
CREATE TABLE `books` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`active` boolean DEFAULT NULL
);
INSERT INTO `books` (`id`, `name`, `active`) VALUES
(1, 'On the Road', 1),
(2, 'Neuromancer', 0),
(3, 'Modern History', 1),
(4, 'Red Mars', 1);
# TRANSACTIONS
CREATE TABLE `transactions` (
`id` int(11) NOT NULL,
`user_1_id` int(11) NOT NULL,
`user_2_id` int(11) DEFAULT NULL,
`book_id` int(11) DEFAULT NULL,
`timestamp` varchar(20) DEFAULT NULL,
`type` enum('Rent', 'Sold') NOT NULL
);
INSERT INTO `transactions` (`id`, `user_1_id`, `user_2_id`, `book_id`, `timestamp`, `type`) VALUES
(1, 1, 2, 1, '1465238591', 'Rent'),
(2, 2, 1, 2, '1465238592', 'Rent'),
(3, 2, 3, 3, '1465238593', 'Rent'),
(4, 3, 4, NULL, '1465238594', 'Sold'),
(5, 2, 3, NULL, '1465238595', 'Sold'),
(6, 3, 4, NULL, '1465238596', 'Sold'),
(7, 2, 2, 4, '1465238597', 'Rent'),
(8, 1, 3, 1, '1465238598', 'Rent'),
(9, 2, 4, 2, '1465238598', 'Rent');
# RELATIONSHIPS
CREATE TABLE `relationships` (
`id` int(11) NOT NULL,
`user_1_id` int(11) DEFAULT NULL,
`user_2_id` int(11) NOT NULL,
`type` enum('Customer', 'Supplier') NOT NULL
);
INSERT INTO `relationships` (`id`, `user_1_id`, `user_2_id`, `type`) VALUES
(1, 1, 2, 'Customer'),
(2, 2, 1, 'Customer'),
(3, 2, 4, 'Customer'),
(3, 1, 4, 'Supplier'),
(3, 3, 1, 'Customer');
Query:
SELECT DISTINCT
t.id,
t.type,
t.timestamp,
u1.name as user_1_name,
u2.name as user_2_name,
b.name as book_name
FROM transactions t
LEFT JOIN relationships r ON (r.user_1_id = 1 AND r.type = 'Customer')
LEFT JOIN books b ON (b.id = t.book_id AND b.active)
LEFT JOIN users u1 ON (u1.id = t.user_1_id) # AND u1.active
LEFT JOIN users u2 ON (u2.id = t.user_2_id) # AND u2.active
WHERE (r.user_2_id = t.user_1_id OR t.user_2_id = 1 AND t.user_1_id != 1)
# AND b.active AND u1.active AND u2.active
[Result]:
| id | type | timestamp | user_1_name | user_2_name | book_name |
|----|------|------------|-------------|-------------|----------------|
| 3 | Rent | 1465238593 | Alice | Jess | Modern History |
| 2 | Rent | 1465238592 | Alice | John | (null) | <<< Should not be here
| 7 | Rent | 1465238597 | Alice | Alice | Red Mars |
| 5 | Sold | 1465238595 | Alice | Jess | (null) | <<< Correct
| 9 | Rent | 1465238598 | Alice | Bob | (null) | <<< Should not be here
In the above result, the problem is that book Neuromancer has flag 'active' set to 0, so should not appear in the result. I have played with placing AND b.active at different places, but the results are always wrong. (See http://www.sqlfiddle.com/#!9/696ed2/5)
Looking at the mess above, I am not even sure my approach is any good, any suggestions are welcome.
As D. Smania mentioned in comments you need to make sure b.active is either 1 or NULL but based on your LEFT JOIN condition b.active will always be 1 so you need to do the join only on id and rely on the WHERE condition for comparison. This should yield the results you asked for:
SELECT DISTINCT
t.id,
t.type,
t.timestamp,
u1.name AS user_1_name,
u2.name AS user_2_name,
b.name AS book_name
FROM transactions t
LEFT JOIN relationships r ON (r.user_1_id = 1 AND r.type = 'Customer')
LEFT JOIN books b ON (b.id = t.book_id)
LEFT JOIN users u1 ON (u1.id = t.user_1_id)
LEFT JOIN users u2 ON (u2.id = t.user_2_id)
WHERE (r.user_2_id = t.user_1_id OR t.user_2_id = 1 AND t.user_1_id != 1)
AND (b.active OR b.active IS NULL)
AND u1.active AND u2.active
SQL Fiddle
One note - in your first WHERE condition it's not clear to me whether you mean:
(r.user_2_id = t.user_1_id OR (t.user_2_id = 1 AND t.user_1_id != 1))
or
((r.user_2_id = t.user_1_id OR t.user_2_id = 1) AND t.user_1_id != 1)
It's always best to be explicit with your logic grouping when you have adjacent AND and OR conditions.
I have below tables
tbl_user
uid first_name last_name email_id
1 steve martin steve1#gmail.com
2 mark lee mark1#gmail.com
3 nelson wise nelson23#gmail.com
tbl_tier
tier_id tier_name points_required
1 Silver 100
2 Gold 200
3 Platinum 300
tbl_tier_earned
id tier_id uid
1 1 1
2 2 1
3 3 1
4 1 2
5 2 2
6 1 3
I need unique users with their current tiers like:
first_name last_name email_id current_tier
steve martin steve1#gmail.com Platinum
mark lee mark1#gmail.com Gold
I have tried below query but it gives me only 1 result:
SELECT u.first_name,u.last_name,u.email_id, t.tier_name
FROM tbl_tier_earned AS tte
INNER JOIN tbl_user AS u
ON u.uid = tte.uid
INNER JOIN tbl_tier AS t
ON tte.tier_id = t.tier_id
WHERE u.email_id!=""
ORDER BY t.points_required DESC LIMIT 0,1
How can I retrieve above data using mysql query?
It appears that the current tier is given by the max tier_id in the tbl_tier_earned table, for each user. One approach here would be to join the user table to a subquery on the tbl_tier_earned table which finds the max tier.
SELECT
u.first_name,
u.last_name,
u.email_id,
COALESCE(t2.tier_name, 'NA') AS current_tier
FROM tbl_user u
LEFT JOIN
(
SELECT uid, MAX(tier_id) AS max_tier_id
FROM tbl_tier_earned
GROUP BY uid
) t1
ON u.uid = t1.uid
LEFT JOIN tbl_tier t2
ON t1.max_tier_id = t2.tier_id;
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE tbl_user
(`uid` int, `first_name` varchar(6), `last_name` varchar(6), `email_id` varchar(18))
;
INSERT INTO tbl_user
(`uid`, `first_name`, `last_name`, `email_id`)
VALUES
(1, 'steve', 'martin', 'steve1#gmail.com'),
(2, 'mark', 'lee', 'mark1#gmail.com'),
(3, 'nelson', 'wise', 'nelson23#gmail.com')
;
CREATE TABLE tbl_tier
(`tier_id` int, `tier_name` varchar(8), `points_required` int)
;
INSERT INTO tbl_tier
(`tier_id`, `tier_name`, `points_required`)
VALUES
(1, 'Silver', 100),
(2, 'Gold', 200),
(3, 'Platinum', 300)
;
CREATE TABLE tbl_tier_earned
(`id` int, `tier_id` int, `uid` int)
;
INSERT INTO tbl_tier_earned
(`id`, `tier_id`, `uid`)
VALUES
(1, 1, 1),
(2, 2, 1),
(3, 3, 1),
(4, 1, 2),
(5, 2, 2),
(6, 1, 3)
;
Query 1:
SELECT c.first_name, c.last_name, c.email_id,
(SELECT tier_name from tbl_tier WHERE points_required = max(b.points_required)) as current_tier
FROM tbl_tier_earned a
INNER JOIN tbl_tier b ON a.tier_id = b.tier_id
INNER JOIN tbl_user c ON a.uid = c.uid
GROUP BY c.first_name, c.last_name, c.email_id
Results:
| first_name | last_name | email_id | current_tier |
|------------|-----------|--------------------|--------------|
| mark | lee | mark1#gmail.com | Gold |
| nelson | wise | nelson23#gmail.com | Silver |
| steve | martin | steve1#gmail.com | Platinum |
I want to run a mysql query to select all rows from a table films where the value of the title column does not exist anywhere in all the values of another column (collection).
Here is a simplified version of my table with content:
mysql> select * from films;
+----+--------------+--------------+
| id | title | collection |
+----+--------------+--------------+
| 1 | Collection 1 | NULL |
| 2 | Film 1 | NULL |
| 3 | Film 2 | Collection 1 |
+----+--------------+--------------+
Here is my query:
mysql> SELECT * FROM films WHERE title NOT IN (SELECT collection FROM films);
Empty set (0.00 sec)
In this example, I would want to select the rows with titles Film 1 and Film 2, but my query is returning no rows.
Here is the table structure:
CREATE TABLE `films` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(200) NOT NULL DEFAULT '',
`collection` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM;
SELECT *
FROM films
WHERE title NOT IN (SELECT collection FROM films where collection is not null);
SQLFiddle: http://sqlfiddle.com/#!2/76278/1
Have you tried using NOT EXISTS:
SELECT *
FROM films f1
WHERE NOT EXISTS (SELECT collection
FROM films f2
WHERE f1.title = f2.collection);
See SQL Fiddle with Demo
If you want to use IN then you will want to look for values that are NOT NULL:
SELECT *
FROM films
WHERE title NOT IN (SELECT collection
FROM films
WHERE collection is not null);
See SQL Fiddle with Demo
The result for both is:
| ID | TITLE | COLLECTION |
------------------------------
| 2 | Film 1 | (null) |
| 3 | Film 2 | Collection 1 |
The problem with your current query is that -- stealing from #Quassnoi's answer here:
Both IN and NOT IN return NULL which is not an acceptable condition for WHERE clause.
Since the null value is being returned by your subquery you want to specifically exclude it.
Another option using an outer join
SELECT f.*
FROM films f LEFT OUTER JOIN films ff
ON f.title = ff.collection
WHERE ff.collection IS NULL
Try this please:
SQLFIDDLE DEMO
Query:
select a.id, a.planid
from one a
left join one b
on a.planid <> b.iid
where not (b.iid is null)
group by b.id
;
Results: based on the sample table I used.
ID PLANID
t15 1
j18 2
EDIT TO ADD : HERE WITH OP SCHEMA
select b.id, b.title
from opschema b
inner join opschema a
on b.title <> a.collection
or b.collection <> a.title
group by b.id
;
OP SHCEMA SQLFIDDLE DEMO
ID TITLE
2 Film 1
3 Film 2
CREATE TABLE IF NOT EXISTS `reservation_tables` (
`res_table_id` int(10) NOT NULL AUTO_INCREMENT,
`res_table_name` int(10) NOT NULL,
`date_time` varchar(20) NOT NULL,
`partyhall_id` int(10) NOT NULL,
`flag` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`res_table_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;
INSERT INTO `reservation_tables` (`res_table_id`, `res_table_name`, `date_time`, `partyhall_id`, `flag`) VALUES
(1, 1, '2014-08-17 12:00 am', 7, '1'),
(2, 2, '2014-08-17 12:00 am', 7, '1'),
(3, 3, '2014-08-18 12:00 am', 8, '1'),
(4, 4, '2014-08-18 12:00 am', 8, '1'),
(5, 1, '2014-08-25 12:00 am', 12, '1'),
(6, 2, '2014-08-25 12:00 am', 12, '1'),
(7, 3, '2014-08-20 12:00 am', 23, '1'),
(8, 4, '2014-08-20 12:00 am', 23, '1');
Ι had to select available table name for matching date_time
Example select available table_name where date_time = 2014-08-18 12:00 am.
solution query is:
im sure this works well
SELECT distinct res_table_name FROM reservation_tables WHERE `res_table_name` NOT IN
(SELECT `res_table_name` FROM reservation_tables where `date_time` = '2014-08-17 12:00 am')