Matching fighters from a single table - mysql

I have a table with fighter records and I need to match them accordingly by level, weight, sex and type of fight sport. This is the structure of the table
CREATE TABLE `tfc_sparring_requests_athletes` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`fullname` varchar(300) DEFAULT NULL,
`birthdate` date DEFAULT NULL,
`weight` float DEFAULT NULL,
`fightsport` int(11) DEFAULT NULL,
`sex` int(11) DEFAULT NULL,
`level` int(11) DEFAULT NULL,
`teamid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8
I tried to make a query like this in order to match the fighters
select a.fullname,b.fullname,a.weight
from tfc_sparring_requests_athletes a ,
tfc_sparring_requests_athletes b
where a.weight = b.weight
and a.fightsport = b.fightsport
and a.level =b.level
and a.sex = b.sex
and a.fullname != b.fullname
and the result is
fighter23 fighter1 78
fighter6 fighter5 70
fighter5 fighter6 70
fighter1 fighter23 78
fighter26 fighter25 57
fighter25 fighter26 57
fighter28 fighter27 80
fighter27 fighter28 80
As you can see fighter 1 is matched with fighter 23 in row 1 but in row 4 fighters appear again. Also other fighters repeat their match as well like fighter 5 and 6 in row 2 and 3. How can I avoid this repetition so I can show the matches uniquely?

Anyway I found the solution based on this question How to select distinct pairs in MySQL join (same table) with transitivity?
select MIN(a.id),b.id,a.fullname name1,b.fullname name2,a.weight
from tfc_sparring_requests_athletes a ,tfc_sparring_requests_athletes b
where a.weight = b.weight
and a.fightsport = b.fightsport
and a.level =b.level
and a.sex = b.sex
and a.fullname != b.fullname
AND b.id > a.id
GROUP BY b.id;

Related

How to get null column when condition doesn't apply with multiple rows results

I am having a hard time trying to figure out how to get the follow query result:
Let me show you the table structure and the query I am using. I think am close to get it right but I need some help figuring out what is wrong:
Here are the tables I have:
CREATE TABLE `manager` (
`man_id` int(11) NOT NULL AUTO_INCREMENT,
`man_firtname` varchar(20) NOT NULL,
`man_lastname` varchar(20) NOT NULL,
PRIMARY KEY (`man_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
man_id man_firtname man_lastname
1 Albert Einstein
CREATE TABLE `orders` (
`ord_id` int(11) NOT NULL AUTO_INCREMENT,
`ord_orderno` varchar(12) NOT NULL,
`ord_man_id` int(11) NOT NULL,
`ord_total` decimal(11,0) NOT NULL,
`ord_code` varchar(10) NOT NULL,
PRIMARY KEY (`ord_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ord_id ord_orderno ord_man_id ord_total ord_code
1 ABCDE 1 160 FFFBBB
CREATE TABLE `orders_items` (
`ori_id` int(11) NOT NULL AUTO_INCREMENT,
`ori_ord_id` int(11) NOT NULL,
`ori_item_code` varchar(10) NOT NULL,
`ori_name` varchar(40) NOT NULL,
`ori_desc` varchar(80) NOT NULL,
PRIMARY KEY (`ori_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ori_id ori_ord_id ori_item_code ori_name ori_desc
1 1 JO123 JohnyT This is a test description
2 1 KK234 SprayC Spray test description
CREATE TABLE `proda` (
`pra_id` int(11) NOT NULL AUTO_INCREMENT,
`pra_code` varchar(10) NOT NULL,
`pra_name` varchar(40) NOT NULL,
PRIMARY KEY (`pra_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
pra_id pra_code pra_name
1 JO123 JohnyT
CREATE TABLE `prodb` (
`prb_id` int(11) NOT NULL AUTO_INCREMENT,
`prb_code` varchar(10) NOT NULL,
`prb_name` varchar(40) NOT NULL,
PRIMARY KEY (`prb_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
prb_id prb_code prb_name
1 KK234 SprayC
CREATE TABLE `special` (
`spe_id` int(11) NOT NULL AUTO_INCREMENT,
`spe_man_id` int(11) NOT NULL,
`spe_code` varchar(10) NOT NULL,
PRIMARY KEY (`spe_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
spe_id spe_man_id spe_code spe_item_code
1 1 FFFBBB JO123
This is the query I have:
SELECT
tbl1.ord_id,
UPPER(tbl1.ord_orderno) As ord_orderno,
tbl1.ord_total,
tbl1.ord_code,
tbl2.ori_id,
tbl2.ori_item_code,
tbl3.pra_name,
tbl4.prb_name
FROM
orders tbl1
JOIN
orders_items tbl2
ON
tbl1.ord_id=tbl2.ori_ord_id
LEFT JOIN
proda tbl3
ON
tbl2.ori_item_code=tbl3.pra_code
LEFT JOIN
prodb tbl4
ON
tbl2.ori_item_code=tbl4.prb_code
JOIN
special tbl5
ON
tbl1.ord_code=tbl5.spe_code
WHERE
tbl1.ord_code IN (SELECT spe_code FROM special JOIN manager ON man_id=1)
AND
tbl1.ord_id=1;
And this is the result I get:
ord_id ord_orderno ord_total ord_code ori_id ori_item_code pra_name prb_name
1 ABCDE 160 FFFBBB 1 JO123 JohnyT
1 ABCDE 160 FFFBBB 2 KK234 SprayC
What I am trying to get instead?
ord_id ord_orderno ord_total ord_code ori_id ori_item_code pra_name prb_name
1 ABCDE 160 FFFBBB 1 JO123 JohnyT
1 ABCDE 160 NULL 2 KK234 SprayC
Basically, the ord_code should only show when there is a match in the special table, otherwise it should be null. Anyone has any idea on what I am doing wrong? Thank you so much
Use tbl5.spe_code instead of tbl1.ord_code in the SELECT list. When there's no match, the LEFT JOIN will return NULL for all the columns in the special table.
You also need to change the columns you're using in the join with special. it should be tbl2.ori_item_code = tbl5.spe_item_code.
And you need to use LEFT JOIN with the special table in order to get non-matching rows.
SELECT
tbl1.ord_id,
UPPER(tbl1.ord_orderno) As ord_orderno,
tbl1.ord_total,
tbl5.spe_code,
tbl2.ori_id,
tbl2.ori_item_code,
tbl3.pra_name,
tbl4.prb_name
FROM
orders tbl1
JOIN
orders_items tbl2
ON
tbl1.ord_id=tbl2.ori_ord_id
LEFT JOIN
proda tbl3
ON
tbl2.ori_item_code=tbl3.pra_code
LEFT JOIN
prodb tbl4
ON
tbl2.ori_item_code=tbl4.prb_code
LEFT JOIN
special tbl5
ON
tbl2.ori_item_code=tbl5.spe_item_code
WHERE
tbl1.ord_code IN (SELECT spe_code FROM special JOIN manager ON man_id=1)
AND
tbl1.ord_id=1;
DEMO

View with join between field that can be null

I have 2 tables with more than 50,000 records each, each one of these.
CREATE TABLE IF NOT EXISTS `call_attempt` (
`csvleads_id_fk` int(11) NOT NULL,
`users_id_fk` int(11) NOT NULL,
`status` int(11) NOT NULL,
`call_id` varchar(50) default NULL,
KEY `csvlead` (`csvleads_id_fk`),
KEY `user_id` (`users_id_fk`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `recorded` (
`record_id` int(11) NOT NULL auto_increment,
`agent_id_fk` int(11) NOT NULL,
`lead_id_fk` int(11) NOT NULL,
`duration` int(11) NOT NULL,
`recording_url` text collate utf8_unicode_ci NOT NULL,
`recorded_at` timestamp NULL default NULL,
`call_id` varchar(50) character set utf8 default NULL,
PRIMARY KEY (`record_id`),
UNIQUE KEY `filterme` (`recording_url`(100))
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=72158 ;
I added a call_id field to make the link. This means that new records must have these fields filled, at least in table call_attempt.
call_attempt recorded
------------------- ----------------
users_id_fk call_id call_id dutarion
------------------- ----------------
1 NULL NULL 10
2 NULL NULL 8
3 NULL NULL 5
4 NULL ca12 19
50000 ca12 ca14 9
50001 ca13
50002 ca14
I need to throw me a view that all records in the table call_attempt, and if you find records in table recorded the duration is brought.
I tried LEFT JOIN but takes more than 50 seconds.
SELECT
`cal`.`csvleads_id_fk` AS `Id`,
`rc`.`duration` AS `duration`
FROM `call_attempt` AS cal
LEFT JOIN recorded AS rc ON (cal.call_id = rc.call_id AND (rc.call_id IS NOT NULL))
84.625 sec / 0.000 sec
Next, I tried doing a LEFT JOIN to a SELECT table recorded with only the records that call_id are NOT NULL but don't let me create the view.
CREATE
ALGORITHM = UNDEFINED
DEFINER = `benscott`#`%`
SQL SECURITY DEFINER
VIEW `callHistory4` AS
SELECT
`cal`.`csvleads_id_fk` AS `Id`,
`rc`.`duration` AS `duration`
FROM `call_attempt` AS cal
LEFT JOIN (SELECT call_id , duration FROM `recorded` WHERE call_id IS NOT NULL) AS rc ON (rc.call_id = cal.call_id)
Error Code: 1349. View's SELECT contains a subquery in the FROM clause
Then I create another view with just the results NOT NULL from call_id.
CREATE
ALGORITHM = UNDEFINED
DEFINER = `benscott`#`%`
SQL SECURITY DEFINER
VIEW `view_recorded` AS
SELECT call_id , duration FROM `recorded` WHERE call_id IS NOT NULL
And in the new view I join with view_recorded but also takes more than 40 seconds.
SELECT
`cal`.`csvleads_id_fk` AS `Id`,
`rc`.`duration` AS `duration`
FROM `call_attempt` AS cal
LEFT JOIN view_recorded AS rc ON (rc.call_id = cal.call_id)
92.094 sec / 0.000 sec
So, what options Do I have? Thank you!!
For this query:
SELECT `cal`.`csvleads_id_fk` AS `Id`, `rc`.`duration` AS `duration`
FROM `call_attempt_log` cal LEFT JOIN
recorded_calls rc
ON cal.call_id = rc.call_id AND rc.call_id IS NOT NULL;
The best index is recorded_calls(call_id, duration).

different values in same column, output in different columns

Currently I am working on a project, which has to do with Formula 1.
That's my structure of the table for results.
CREATE TABLE IF NOT EXISTS `races_results` (
`resultid` int(11) NOT NULL,
`seasonyear` int(4) NOT NULL,
`trackid` tinyint(2) NOT NULL,
`raceid` int(2) NOT NULL,
`session` tinyint(1) NOT NULL,
`q` int(11) NOT NULL,
`place` tinyint(2) NOT NULL,
`driverid` int(2) NOT NULL,
`teamid` int(2) NOT NULL,
`time` int(11) NOT NULL,
`laps` int(2) NOT NULL,
`status` varchar(3) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
My big problem is that I don't get the result in output as I want.
SELECT place, driverid, teamid, if(q=1, time, '') as time1, if(q=2, time, '') as time2, if(q=3, time, '') as time3
FROM `races_results`
WHERE `seasonyear` = 2015 AND `raceid` = 3 AND `session` = 2 AND `q` IN (1,2,3)
GROUP BY driverid
ORDER BY CASE WHEN q = 3 THEN place >= 1 AND place <= 10 END ASC, CASE WHEN q = 2 THEN place >= 11 AND place <= 16 END ASC, CASE WHEN q = 1 THEN place >= 17 AND place <= 22 END ASC
My target is that I want that the all times of a driver will show side by side and after this should be ordered by the participants of the sections.
After this I should have an output like this http://www.formula1.com/content/fom-website/en/championship/results/2015-race-results/2015-japan-results/qualifying.html
From your question I understand that the table races_results has a line for each result, so the times of the different qualifications are on different lines. To get these on one line you can do a join of the same table:
SELECT place, driverid, teamid, r1.time as time1, r2.time as time2, r3.time as time3
FROM races_results r1 LEFT JOIN races_results r2 on (r1.driverid=r2.driverid and r1.raceid=r2.raceid)
LEFT JOIN races_results r3 on (r1.driverid=r3.driverid and r1.raceid=r3.raceid)
WHERE r1.q=1 AND r2.q=2 AND r3.q=3 AND
`seasonyear` = 2015 AND `raceid` = 3 AND `session` = 2
GROUP BY driverid
ORDER BY place;
I assume:
that there is always a result for q=1;
the driverid and raceid are unique for a race on a specific year for a driver;
you want to order by place.

Optimize tables MySQL

I have a query that is executed in 35s, which is waaaaay too long.
Here are the 3 tables concerned by the query (each table is approx. 13000 lines long, and should be much longer in the future) :
Table 1 : Domains
CREATE TABLE IF NOT EXISTS `domain` (
`id_domain` int(11) NOT NULL AUTO_INCREMENT,
`domain_domain` varchar(255) NOT NULL,
`projet_domain` int(11) NOT NULL,
`date_crea_domain` int(11) NOT NULL,
`date_expi_domain` int(11) NOT NULL,
`active_domain` tinyint(1) NOT NULL,
`remarques_domain` text NOT NULL,
PRIMARY KEY (`id_domain`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Table 2 : Keywords
CREATE TABLE IF NOT EXISTS `kw` (
`id_kw` int(11) NOT NULL AUTO_INCREMENT,
`kw_kw` varchar(255) NOT NULL,
`clics_kw` int(11) NOT NULL,
`cpc_kw` float(11,3) NOT NULL,
`date_kw` int(11) NOT NULL,
PRIMARY KEY (`id_kw`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Table 3 : Linking between domain and keyword
CREATE TABLE IF NOT EXISTS `kw_domain` (
`id_kd` int(11) NOT NULL AUTO_INCREMENT,
`kw_kd` int(11) NOT NULL,
`domain_kd` int(11) NOT NULL,
`selected_kd` tinyint(1) NOT NULL,
PRIMARY KEY (`id_kd`),
KEY `kw_to_domain` (`kw_kd`,`domain_kd`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
The query is as follows :
SELECT ng.*, kd.*, kg.*
FROM domain ng
LEFT JOIN kw_domain kd ON kd.domain_kd = ng.id_domain
LEFT JOIN kw kg ON kg.id_kw = kd.kw_kd
GROUP BY ng.id_domain
ORDER BY kd.selected_kd DESC, kd.id_kd DESC
Basically, it selects all domains, with, for each one of these domains, the last associated keyword.
Does anyone have an idea on how to optimize the tables or the query ?
The following will get the last keyword, according to your logic:
select ng.*,
(select kw_kd
from kw_domain kd
where kd.domain_kd = ng.id_domain and kd.selected_kd = 1
order by kd.id_kd desc
limit 1
) as kw_kd
from domain ng;
For performance, you want an index on kw_domain(domain_kd, selected_kd, kw_kd). In this case, the order of the fields matters.
You can use this as a subquery to get more information about the keyword:
select ng.*, kg.*
from (select ng.*,
(select kw_kd
from kw_domain kd
where kd.domain_kd = ng.id_domain and kd.selected_kd = 1
order by kd.id_kd desc
limit 1
) as kw_kd
from domain ng
) ng left join
kw kg
on kg.id_kw = ng.kw_kd;
In MySQL, group by can have poor performance, so this might work better, particularly with the right indexes.

Assistance with MySQL JOIN

I have two tables, one with categories and subcategories. Each category and subcategory has an id and if it's a subcategory, it's got a topid != 0 referring what it's a subcategory of. The other table "markers" has a field 'cat' which correlates with the category field 'name' Now I want to select everything from markers with category.id = 4 OR category.topid = 4 so I tried this query:
SELECT * FROM `xymply_markers`
JOIN `xymply_categories`
ON xymply_markers.cat = xymply_categories.name
WHERE xymply_categories.topid=4
OR xymply_categories.id=4
Which doesn't return me anything even tho I do have such elements in my table "markers". Any assistance would be appreciated!
Table schemas:
`xymply_categories` (
`id` int(11) NOT NULL auto_increment,
`topid` int(11) NOT NULL,
`name` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 AUTO_INCREMENT=15 ;
`xymply_markers` (
`created` date NOT NULL,
`id` int(11) NOT NULL auto_increment,
`sdate` date NOT NULL,
`hdate` date NOT NULL,
`name` varchar(60) NOT NULL,
`address` varchar(80) NOT NULL,
`unit` varchar(6) NOT NULL,
`lat` decimal(10,7) NOT NULL,
`lng` decimal(10,7) NOT NULL,
`type` varchar(30) NOT NULL,
`userid` int(11) NOT NULL,
`adtext` text NOT NULL,
`phone` varchar(20) NOT NULL,
`email` varchar(30) NOT NULL,
`url` varchar(30) NOT NULL,
`cat` varchar(4) NOT NULL,
UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=151 DEFAULT CHARSET=utf8 AUTO_INCREMENT=151 ;
Sample Data:
xymply_categories:
id 1
topid 0
name 'vehicle'
--------------
id 2
topid 1
name 'bike'
--------------
id 3
topid 1
name 'truck'
xymply_markers:
id 1
sdate 2012-03-01
hdate 2012-04-01
name 'TEST'
address '1234 TEST'
unit''
lat 49.0
lng -123.0
adtext 'TEST'
phone '1234567890'
email 'email#email.com'
url 'www.url.com'
cat 'bike'
--------------
id 1
sdate 2012-03-01
hdate 2012-04-01
name 'TEST'
address '1234 TEST'
unit''
lat 49.5
lng -123.5
adtext 'TEST'
phone '1234567890'
email 'email#email.com'
url 'www.url.com'
cat 'vehicle'
One problem is that the xymply_markers.cat field is VARCHAR(4) but the xymply_categories.name field is TEXT, and contains values longer than 4 characters. Either you're not giving us the accurate schema, or you're confused about which columns join, or you're never going to see any trucks or vehicles. Columns which join should have the same type almost without exception (I've never seen a good reason for an exception).
You are then asking about id = 4 or topid = 4, but the sample data you show only has id = 1 or topid = 1. Do you actually have data where id = 4 or topid = 4 in the system?
Between these two lots of confusion, it is hard to know what we're up against. If you have data that joins and has the relevant topid or id values, then your query should work.
I have a field called 'id' in both tables. How can I control which one I'm accessing with PHP after I read data into the array with $row = #mysql_fetch_assoc($result)?
The simplest way is to ensure that each result column has a unique name, creating one with an 'alias', as in:
SELECT c.id AS category_id,
c.topid,
c.name AS category_name,
m.id AS marker_id,
m.name AS marker_name,
...
PHP will associate the alias names with the the data in the row.