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 |
Related
I have three tables. FirstTable is like this:
id
id2
id3
message
info
1
0
2
hello!
none
2
1
0
hi there
none
3
0
3
hi man
none
SecondTable is:
id2
name
1
Alex
2
Bob
ThirdTable is:
id3
name
1
Rob
2
Tom
3
Joe
As you can see, in FirstTable always only one of id2 and id3 column's values is not zero. So, I want to get the result as below:
1 - Tom - hello!
or
2 - Alex - hi there
or
3 - Joe - hi man
I cannot use a query like
SELECT
FirstTable.id AS id, FirstTable.message AS message,
FirstTable.info AS info,
SecondTable.name AS name1,
ThirdTable.name AS name2,
FROM
FirstTable, SecondTable, ThirdTable
WHERE
FirstTable.id = 1
AND FirstTable.id2 = SecondTable.id2
AND FirstTable.id3 = ThirdTable.id3
ORDER BY
FirstTable.id DESC
because I do not have 0 only one of id2/id3 in FirstTable. What is the right query to get something like
1 - Tom - hello!
? Thanks
You can accoumplish that by using two LEFT JOINs
CREATE TABLE table1
(`id` int, `id2` int, `id3` int, `message` varchar(8), `info` varchar(4))
;
INSERT INTO table1
(`id`, `id2`, `id3`, `message`, `info`)
VALUES
(1, 0, 2, 'hello!', 'none'),
(2, 1, 0, 'hi there', 'none'),
(3, 0, 3, 'hi man', 'none')
;
CREATE TABLE table2
(`id2` int, `name` varchar(4))
;
INSERT INTO table2
(`id2`, `name`)
VALUES
(1, 'Alex'),
(2, 'Bob')
;
CREATE TABLE table3
(`id3` int, `name` varchar(3))
;
INSERT INTO table3
(`id3`, `name`)
VALUES
(1, 'Rob'),
(2, 'Tom'),
(3, 'Joe')
;
SELECT t1.`id`,
CASE WHEN t1.id2 = 0 THEN t3.`name`
ELSE t2.`name`END name,
t1.message
FROM table1 t1 LEFT JOIN table2 t2 ON t1.id2=t2.id2 LEFT JOIN table3 t3 ON t1.id3 = t3.id3
id | name | message
-: | :--- | :-------
1 | Tom | hello!
2 | Alex | hi there
3 | Joe | hi man
db<>fiddle here
I want to Join to table. the condition is I want to only join those rows which have only one row to match. eg.
books:
id | name | price
1 | book1 | 19
2 | book2 | 19
3 | book3 | 30
price_offer:
id | offer | price
1 | offer1 | 19
2 | offer2 | 30
so now if I do select query on these table:
SELECT * FROM price_offer
JOIN books ON price_offer.price = books.price
I only want to join book with id 3 as it have only one match with price_offer table.
You could use a self join for books table to pick a book with only single match
select po.*, b1.*
from price_offer po
join books b1 on po.price = b1.price
join (
select price,max(id) id
from books
group by price
having count(*) = 1
) b2 on b1.id = b2.id
Demo
Try following query:
Sample data:
create table books(id int, name varchar(10), price int);
insert into books values
(1, 'book1', 19),
(2, 'book2', 19),
(3, 'book3', 30);
create table price_offer(id int, offer varchar(10), price int);
insert into price_offer values
(1, 'offer1', 19),
(2, 'offer2', 30);
Query:
select max(b.id)
from price_offer p
left join books b on b.price = p.price
where p.id is not null
group by b.price
having count(*) = 1;
If you want to avoid nesting queries where you have to use self-joins, you can use window-functions of MySQL 8.0.11, which are exactly for cases like this
Anyone up to an SQL challenge? Cause all my efforts so far are barely enough to simplify the problem and put it in a question...
Here it goes. In the example below we need to include:
All paid flights
Flights to a country (paid or not) if a person has made another flight to a paid city in that country
It's already tricky, but there is more to it.
If a person flies to a city with no entry fee, but it is located in a
country that DOES have a fee, that flight is still considered paid
and must be included as well.
EDIT: I've added flight 110, which should help reveal unnecessarily added free fligts.
Below is the result set that should come out of the SQL query:
+--------------------------------------------------------------+
| Desired result set |
+--------------------------------------------------------------+
| FlightNumber | ID | Name | LocationID | location.Name |
+--------------------------------------------------------------+
| 102 | 2 | Tom | 500 | NL - NoFee | -> because Tom has a paid flight to Amsterdam
| 103 | 2 | Tom | 501 | Amsterdam (NL) - Fee | -> because Amsterdam is a paid location
| 105 | 4 | Bob | 501 | Amsterdam (NL) - Fee | -> because Amsterdam is a paid location
| 107 | 6 | Bill | 503 | ITA - Fee | -> because ITA is a paid location
| 108 | 7 | Ryan | 503 | ITA - Fee | -> because ITA is a paid location
| 109 | 7 | Ryan | 505 | Venice (ITA) - NoFee | -> because Venice is located inside ITA
+--------------------------------------------------------------+
Does anyone know how get this sweet result set with SQL?
A good place to start:
SELECT flights.FlightNumber, people.ID, people.Name, flights.LocationID, locations.Name
FROM flights
INNER JOIN people ON (people.ID = flights.ID)
INNER JOIN locations ON (locations.LocationID = flights.LocationID)
CREATE/INSERT
CREATE TABLE `people` (
`ID` INT NOT NULL,
`Name` VARCHAR(45) NULL,
PRIMARY KEY (`ID`) );
CREATE TABLE `locations` (
`LocationID` INT NOT NULL,
`Name` VARCHAR(45) NULL,
`EntryFee` TINYINT(1) NULL,
`ParentLocationID` INT NULL,
PRIMARY KEY (`LocationID`) );
CREATE TABLE `flights` (
`FlightNumber` INT NOT NULL,
`ID` INT NULL,
`LocationID` INT NULL,
PRIMARY KEY (`FlightNumber`) ,
INDEX `fk_purchases_buyers_idx` (`LocationID` ASC) ,
INDEX `fk_flights_people1_idx` (`ID` ASC) ,
CONSTRAINT `fk_purchases_buyers`
FOREIGN KEY (`LocationID`)
REFERENCES `locations` (`LocationID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_flights_people1`
FOREIGN KEY (`ID`)
REFERENCES `people` (`ID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
INSERT INTO `people` (`ID`, `Name`) VALUES
(1, 'John'),
(2, 'Tom'),
(3, 'Kate'),
(4, 'Bob'),
(5, 'Mike'),
(6, 'Bill'),
(7, 'Ryan');
INSERT INTO `locations` (`LocationID`, `Name`, `EntryFee`, `ParentLocationID`) VALUES
(500, 'NL - NoFee', 0, NULL),
(501, 'Amsterdam (NL) - Fee', 1, 500),
(502, 'Rotterdam (NL) - NoFee', 0, 500),
(503, 'ITA - Fee', 1, NULL),
(504, 'Rome (ITA) - Fee', 1, 503),
(505, 'Venice (ITA) - NoFee', 0, 503);
INSERT INTO `flights` VALUES
(100, 1, 500),
(101, 1, 502),
(102, 2, 500),
(103, 2, 501),
(104, 3, 500),
(105, 4, 501),
(106, 5, 502),
(107, 6, 503),
(108, 7, 503),
(109, 7, 505),
(110, 6, 502);
Unimportant note: I know this example is not completely logical in a sense of storing countries and cities in the same table and having flight records to a country and to a city. But this is just an example. At least it's more readable than t1.col1-like stuff.
Following should work :
SELECT F.FlightNumber, P.ID, P.Name, F.LocationID, LOC.Name AS Loc_Name
FROM flights F
INNER JOIN people P ON P.ID = F.ID
INNER JOIN (SELECT L1.LocationID, L1.`Name`, L1.`ParentLocationID`
FROM locations L1
LEFT JOIN locations L2 ON L1.`ParentLocationID` = L2.LocationID
WHERE L1.`EntryFee` = 1 OR L2.`EntryFee` = 1) AS LOC ON LOC.LocationID = F.LocationID
UNION
SELECT F.FlightNumber, PAID_FL.ID, PAID_FL.Name, F.LocationID, PAID_FL.Loc_Name
FROM flights F
INNER JOIN (SELECT F.FlightNumber, P.ID, P.Name, LOC.Name AS Loc_Name,LOC.`ParentLocationID` AS LocationID
FROM flights F
INNER JOIN people P ON P.ID = F.ID
INNER JOIN (SELECT L1.LocationID, L1.`ParentLocationID`, L2.`Name`
FROM locations L1
LEFT JOIN locations L2 ON L1.`ParentLocationID` = L2.LocationID
WHERE L1.`EntryFee` = 1 OR L2.`EntryFee` = 1) AS LOC ON LOC.LocationID = F.LocationID) PAID_FL ON F.ID = PAID_FL.ID AND F.LocationID = PAID_FL.LocationID
I didn't do any testing, but I think this will work:
SELECT F.FlightNumber, P.ID, P.Name, L.LocationID, L.Name
FROM flights F
INNER JOIN people P ON P.ID = F.ID
INNER JOIN locations L ON L.LocationID = F.LocationID
WHERE P.ID IN (SELECT F.ID FROM flights F INNER JOIN locations L ON L.LocationID = F.LocationID WHERE L.EntryFee = 1)
See it at SQLFiddle.com.
SELECT x.*
, COALESCE(y.entryfee,x.entryfee,0) fee
FROM locations x
LEFT
JOIN locations y
ON y.parentlocationid = x.locationid;
I want to do subquery with 3 tables and using where in multi values but I always get syntax error. I have to do reporting in Report Builder 3.0
Table A: record_id, Surname, Given Name
Table C: row_id, competency_code, competency_name
Table PC: link_id, record_id, row_id, attainment_date
I would like to join the tables into 1 table. One person will have some completion of competency_code and different with other person. the completion of competency_code based on the attainment_date. I also think to use iff function for attainment_date in competency_code value as complete/yes.
The table that I would like to create is:
Record_Id | Surname | GivenName | Code 1 | Code 2 | Code 3 | Code 4 | Code 5
01 | AA | AA | Complete | Complete | Complete | | Complete
02 | BB | BB | Complete | Complete | | Complete |
03 | CC | CC | | Complete | Complete | | Complete
here is the query that I tried to do.
select distinct a.id, a.surname, a.given_name
from all a
join
(
select pc.attainment_date
from personnel_competency pc
join
(
select c.code, c.name
from competency c)
competency c on (c.row_no = pc.linkid)
)
personnel_competency pc on (pc.id = a.id)
where c.code in ('ABC', 'BCD', 'ABE', 'DEA', 'DEF', 'POS', 'SAQ', 'LOP')
and pc.attainment_date < now()
order by a.record_id
My skill in SQL is very basic. Whether other ways to make the table like that?
Are you looking for a SQL to get your result. If so I think this is what you are looking for ..
It would help if you posted some sample data.
You can test it at
SQLFiddle
Here is the script ..
-- Generate schema and data
create table tableA (id int, surname varchar(30), given_name varchar(30));
create table tablePC (link_id int, id int, attainment_date datetime);
create table tableC (row_id int, competency_code varchar(20), Competency_name varchar(30));
insert into tableA (id, surname, given_name)
values (1, 'AA', 'AAgn')
, (2, 'BB', 'BBgn')
insert into tablePC (link_id, id, attainment_date)
values (1, 1, '2014-09-11')
, (2, 1, '2014-09-10')
, (3, 2, '2014-09-11')
insert into tableC (row_id, competency_code, Competency_name)
values (1, 'ABC', 'completed\Yes')
, (1, 'BCD', 'completed')
, (1, 'ABE', 'completed')
, (2, 'ABC', 'completed')
, (2, 'BCD', 'completed')
, (3, 'ABC', 'completed')
, (3, 'ABE', 'completed')
-- ===============
select *
from tableA TA
inner join tablePC PC
on TA.id = PC.id
inner join
(
select row_id, [ABC] as ABC, [BCD] as BCD, [ABE] as ABE
from tableC TC
pivot
(
max(Competency_name)
for Competency_code in ([ABC], [BCD], [ABE])
) as TCPVT
) TC
on PC.link_id = TC.row_id
where PC.attainment_date < GETDATE()
I have one table called Employee that contains the following information like
ID Name Skills
1 xyz java,php,dotnet
2 abc ruby,java,python
Skills column saves comma seprated values. it could be one or more.
I want to design a query based on OR operate.When user search java, Database displays two employees likes xyz, abc.
I have tried this query but no result comes out:
SELECT m
FROM Employee m
Where m.Skills LIKE '%JAVA% MS PAINT%'
Any Suggestion?
Ideally you should not store the data in a comma-separated list. You should create a join table between the employees and the skills:
CREATE TABLE employees (`e_id` int, `e_name` varchar(3));
INSERT INTO employees (`e_id`, `e_name`)
VALUES
(1, 'xyz'),
(2, 'abc');
CREATE TABLE skills (`s_id` int, `s_name` varchar(6));
INSERT INTO skills (`s_id`, `s_name`)
VALUES
(1, 'java'),
(2, 'php'),
(3, 'dotnet'),
(4, 'ruby'),
(5, 'python');
CREATE TABLE employees_skills (`e_d` int, `s_id` int);
INSERT INTO employees_skills
(`e_d`, `s_id`)
VALUES
(1, 1),
(1, 2),
(1, 3),
(2, 4),
(2, 1),
(2, 5);
Then when you want to select from the tables you will use:
select *
from employees e
inner join employees_skills es
on e.e_id = es.e_id
inner join skills s
on es.s_is = s.s_id
where s.s_name in ('java', 'ruby')
Or you can use the OR clause:
select *
from employees e
inner join employees_skills es
on e.e_id = es.e_id
inner join skills s
on es.s_is = s.s_id
where s.s_name = 'java'
or s.s_name = 'ruby'
use like not good solution. Full scan and slow query.
Create new table with catalog of skills.
Create table user_skills
You should set up your tables like this:
Employee:
ID | Name
---+------
1 | xyz
2 | abc
Skill:
ID | Name
---+------
1 | java
2 | php
3 | dotnet
4 | ruby
5 | python
EmployeeSkills:
ID | EmployeeID | SkillID
---+------------+----------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 4
5 | 2 | 1
6 | 2 | 5
the query to find employees with skills in java would look like this
SELECT
E.Name
FROM
Employee AS E
INNER JOIN
EmployeeSkill AS ES
ON
ES.EmployeeID = E.ID
INNER JOIN
Skill AS S
ON
ES.SkillID = S.ID
WHERE
S.Name = 'java'
select name from table where skill like '%java%' should do