MySQL: Removing duplicate columns on Left Join, 3 tables - sql

I have a table that uses 3 foreign keys into other tables. When I perform a left join, I get duplicate columns. MySQL says that the USING syntax will reduce the duplicate columns, but there aren't examples for multiple keys.
Given:
mysql> describe recipes;
+------------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+-------+
| ID_Recipe | int(11) | NO | PRI | NULL | |
| Recipe_Title | char(64) | NO | | NULL | |
| Difficulty | int(10) unsigned | NO | | NULL | |
| Elegance | int(10) unsigned | NO | | NULL | |
| Quality | int(10) unsigned | NO | | NULL | |
| Kitchen_Hours | int(10) unsigned | NO | | NULL | |
| Kitchen_Minutes | int(10) unsigned | NO | | NULL | |
| Total_Hours | int(10) unsigned | NO | | NULL | |
| Total_Minutes | int(10) unsigned | NO | | NULL | |
| Serving_Quantity | int(10) unsigned | NO | | NULL | |
| Description | varchar(128) | NO | | NULL | |
| ID_Prep_Text | int(11) | YES | | NULL | |
| ID_Picture | int(11) | YES | | NULL | |
| Category | int(10) unsigned | NO | | NULL | |
| ID_Reference | int(11) | YES | | NULL | |
+------------------+------------------+------+-----+---------+-------+
15 rows in set (0.06 sec)
mysql> describe recipe_prep_texts;
+------------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+---------------+------+-----+---------+-------+
| ID_Prep_Text | int(11) | NO | PRI | NULL | |
| Preparation_Text | varchar(2048) | NO | | NULL | |
+------------------+---------------+------+-----+---------+-------+
2 rows in set (0.02 sec)
mysql> describe recipe_prep_texts;
+------------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+---------------+------+-----+---------+-------+
| ID_Prep_Text | int(11) | NO | PRI | NULL | |
| Preparation_Text | varchar(2048) | NO | | NULL | |
+------------------+---------------+------+-----+---------+-------+
2 rows in set (0.02 sec)
mysql> describe mp_references;
+--------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------+------+-----+---------+-------+
| ID_Reference | int(11) | NO | PRI | NULL | |
| ID_Title | int(11) | YES | | NULL | |
| ID_Category | int(11) | YES | | NULL | |
+--------------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
My query statement:
SELECT *
FROM Recipes
LEFT JOIN (Recipe_Prep_Texts, Recipe_Pictures, mp_References)
ON (
Recipe_Prep_Texts.ID_Prep_Text = Recipes.ID_Prep_Text AND
Recipe_Pictures.ID_Picture = Recipes.ID_Picture AND
mp_References.ID_Reference = Recipes.ID_Reference
);
My objective is to get one row of all the columns from the join without duplicate columns. I'm using MySQL C++ Connector to send the SQL statements and retrieve result sets. I believe that the C++ Connector is having issues with duplicate column names.
So what is the SQL statement syntax that I should use?
Reference to MySQL JOIN syntax

I believe the following should work:
SELECT *
FROM Recipes
LEFT JOIN Recipe_Prep_Texts USING (ID_Prep_Text)
LEFT JOIN Recipe_Pictures USING (ID_Picture)
LEFT JOIN mp_References USING (ID_Reference)

Since it looks like most of the tables you are joining on have a few columns except for the first one, how about:
SELECT Recipes.*,
Recipe_Prep_Texts.Preparation_Text,
Recipe_Pictures.Foo, -- describe is missing in OP
mp_References.ID_Title,
mp_References.ID_Category
FROM Recipes
LEFT JOIN (Recipe_Prep_Texts, Recipe_Pictures, mp_References)
ON (
Recipe_Prep_Texts.ID_Prep_Text = Recipes.ID_Prep_Text AND
Recipe_Pictures.ID_Picture = Recipes.ID_Picture AND
mp_References.ID_Reference = Recipes.ID_Reference
);
I can't tell you how many times I wished I had
SELECT (* - foo) FROM table
especially in cases where foo is some huge field like a BLOB and I just want to see everything else without breaking the formatting.

You are selecting * from the combined resulting table. Limit that * to whatever columns you want to keep.

Try the following query:
SELECT name,ac,relation_name
FROM table1
LEFT JOIN table2 USING (ID_Prep_Text)
LEFT JOIN table3 USING (ID_Picture);

Related

SQL select to print all host names in Icinga2 hostgroup

select alias from icinga_hosts; prints all the host names in every hostgroup.
select alias from icinga_hostgroups; prints all the hostgroups.
I can't see how to "select select alias from icinga_hosts where icinga_hostgroups is "customer0";
In other words, 'print all the hostnames in hostgroup customer0'.
Do I need a join of some sort? This is MariaDB 5.5. Thanks for any advice.
MariaDB [icinga]> show fields in icinga_hostgroups;
+---------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------------------+------+-----+---------+----------------+
| hostgroup_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| instance_id | bigint(20) unsigned | YES | MUL | 0 | |
| config_type | smallint(6) | YES | | 0 | |
| hostgroup_object_id | bigint(20) unsigned | YES | | 0 | |
| alias | varchar(255) | YES | | | |
| notes | text | YES | | NULL | |
| notes_url | text | YES | | NULL | |
| action_url | text | YES | | NULL | |
| config_hash | varchar(64) | YES | | NULL | |
+---------------------+---------------------+------+-----+---------+----------------+
9 rows in set (0.00 sec)
show fields in icinga_hosts;
+-----------------------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------------------+---------------------+------+-----+---------+----------------+
| host_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| instance_id | bigint(20) unsigned | YES | MUL | 0 | |
| config_type | smallint(6) | YES | | 0 | |
| host_object_id | bigint(20) unsigned | YES | MUL | 0 | |
| alias | varchar(255) | YES | | | |
| display_name | varchar(255) | YES | | | |
| address | varchar(128) | YES | | | |
select oh.name1 as host_name, ohg.name1 as hostgroup_name
from icinga_hosts h
join icinga_objects oh on h.host_object_id=oh.object_id
join icinga_hostgroup_members hgm on hgm.host_object_id=h.host_object_id
join icinga_hostgroups hg on hg.hostgroup_id=hgm.hostgroup_id
join icinga_objects ohg on hg.hostgroup_object_id=ohg.object_id
where ohg.name1='linux-servers';
You need the icinga_hostgroup_members table like:
SELECT groups.alias AS 'Group',
hosts.alias AS Host
FROM icinga_hosts AS hosts
JOIN icinga_hostgroup_members AS group_members
ON hosts.host_object_id = group_members.host_object_id
JOIN icinga_hostgroups AS groups
ON group_members.hostgroup_id = groups.hostgroup_id
WHERE groups.alias = 'customer0';

Restoring SQL table into new table with more columns

I'm trying to salvage a Gitorious installation that has gone bad. I've dumped the SQL table using mysqldump, but now I'm running into the problem that the new version of Gitorious changed its SQL schema in a few places.
In particular, the old version has a table taggings, which looks like
mysql> describe taggings;
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| tag_id | int(11) | YES | MUL | NULL | |
| taggable_id | int(11) | YES | MUL | NULL | |
| taggable_type | varchar(255) | YES | | NULL | |
| created_at | datetime | YES | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
In the new version, this table has gotten three extra columns:
mysql> describe taggings;
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| tag_id | int(11) | YES | MUL | NULL | |
| taggable_id | int(11) | YES | MUL | NULL | |
| taggable_type | varchar(255) | YES | | NULL | |
| created_at | datetime | YES | | NULL | |
| tagger_id | int(11) | YES | | NULL | |
| tagger_type | varchar(255) | YES | | NULL | |
| context | varchar(255) | YES | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)
so that
grep 'INSERT INTO `taggings`' inuse.sql | mysql -uroot gitorious_production
fails with
ERROR 1136 (21S01) at line 1: Column count doesn't match value count at row 1
Is there an easy way to tell MySQL that the final two fields should be left at their default value, NULL?
(The new Gitorious' taggings table starts out empty.)
As a general best practice, you should mention the field names in which you're inserting :
Insert into taggings (id,tag_id,taggable_id,taggable_type,created_at) values (...your values...)
Rename your new table taggings as taggings_old
Create a table named taggings with your old schema
Insert your data
Add the new column to your table taggings

SQL multiple inclusive joins

Below is schema description. I would like to construct a query that for a given user will return all the cases that are shared directly via case_users OR indirectly via case_groups table. Here is my attempt, where I pull the groups the user belongs to upfront:
SELECT * FROM `cases`
INNER JOIN `case_users` ON `cases`.`id` = `case_users`.`case_id`
INNER JOIN `case_groups` ON `cases`.`id` = `case_groups`.`case_id`
WHERE `case_users`.`user_id` = '<USER_ID>'
OR `case_groups`.`group_id` IN (<USER_GROUP_LIST>)
EXPLAIN returns the following: Impossible WHERE noticed after reading const table...
How can I get it done? Ideally I would like to retrieve all the cases in a single shot - without pulling the USER_GROUP_LIST - groups that the user belongs to.
mysql> describe users;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
+-------------+--------------+------+-----+---------+----------------+
mysql> describe cases;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
+-------------+--------------+------+-----+---------+----------------+
mysql> describe case_users;
+-------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+-------+
| user_id | int(11) | NO | PRI | NULL | |
| case_id | int(11) | NO | PRI | NULL | |
+-------------+---------+------+-----+---------+-------+
mysql> describe case_groups;
+-------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+-------+
| case_id | int(11) | NO | PRI | NULL | |
| group_id | int(11) | NO | PRI | NULL | |
+-------------+---------+------+-----+---------+-------+
mysql> describe group_users;
+-------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+-------+
| group_id | int(11) | NO | PRI | NULL | |
| user_id | int(11) | NO | PRI | NULL | |
+-------------+---------+------+-----+---------+-------+
Your joins will only return cases whose Id is in both the case_users and case_groups..
If its one or the other, then you need 2 queries, which you can UNION to get all the results in a single resultset:
SELECT `cases`.* FROM `cases`
INNER JOIN `case_users` ON `cases`.`id` = `case_users`.`case_id`
WHERE `case_users`.`user_id` = '<USER_ID>'
UNION
SELECT `cases`.* FROM `cases`
INNER JOIN `case_groups` ON `cases`.`id` = `case_groups`.`case_id`
WHERE `case_groups`.`group_id` IN (SELECT `group_users`.`group_id`
FROM `group_users`
WHERE `group_users`.`user_id` = '<USER_ID>')

mysql three joins

I have a problem with mysql
I have 3 tables:
Deposit
+-------------------+-------------+------+-----+
| Field | Type | Null | Key |
+-------------------+-------------+------+-----+
| id | bigint(20) | NO | PRI |
| status | int(2) | NO | |
| depositDate | datetime | NO | MUL |
| reversePayment_id | bigint(20) | YES | UNI |
| claim_id | int(2) | NO | UNI |
| payment_id | bigint(20) | YES | UNI |
+-------------------+-------------+------+-----+
Payment
+--------------------------+---------------+------+-----+
| Field | Type | Null | Key |
+--------------------------+---------------+------+-----+
| id | int(10) | NO | PRI |
| paymentDate | timestamp | NO | MUL |
| pin | int(10) | NO | MUL |
| balanceChange | decimal(15,2) | YES | |
Claim
+------------------------+--------------+------+-----+
| Field | Type | Null | Key |
+------------------------+--------------+------+-----+
| id | int(11) | NO | PRI |
| fullName | varchar(100) | NO | |
| depositSum | blob | NO | |
| ip | varchar(39) | NO | |
| status | int(2) | NO | |
+------------------------+--------------+------+-----+
I try to select deposits (with claims) payment or reversePayment were between two dates, I perform this query with 3 joins:
EXPLAIN SELECT this_.id AS id60_3_, ..., fcpayment2_.id AS id59_0_, ..., reversepay3_.id AS id59_1_, ..., cl1_.id AS id61_2_, ...
FROM Deposit this_
INNER JOIN Payment fcpayment2_ ON this_.payment_id = fcpayment2_.id
LEFT OUTER JOIN Payment reversepay3_ ON this_.reversePayment_id = reversepay3_.id
INNER JOIN Claim cl1_ ON this_.claim_id = cl1_.id
WHERE (
(
fcpayment2_.paymentDate >= '2010-08-04 21:00:00'
AND fcpayment2_.paymentDate <= '2010-08-05 08:01:00'
)
OR (
reversepay3_.paymentDate >= '2010-08-04 21:00:00'
AND reversepay3_.paymentDate <= '2010-08-05 08:01:00'
)
)
ORDER BY this_.depositDate DESC
the result is
+----+-------------+--------------+--------+--------------------------------------------------------------------+----------+---------+-----------------------------------------+--------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+--------+--------------------------------------------------------------------+----------+---------+-----------------------------------------+--------+---------------------------------+
| 1 | SIMPLE | cl1_ | ALL | PRIMARY | NULL | NULL | NULL | 426588 | Using temporary; Using filesort |
| 1 | SIMPLE | this_ | eq_ref | claim_id,payment_id,FKDB5A0548511B6CDD,FKDB5A054867BA4108 | claim_id | 4 | portal.cl1_.id | 1 | |
| 1 | SIMPLE | fcpayment2_ | eq_ref | PRIMARY,paymentDate,date | PRIMARY | 4 | portal.this_.payment_id | 1 | Using where |
| 1 | SIMPLE | reversepay3_ | eq_ref | PRIMARY | PRIMARY | 4 | portal.this_.reversePayment_id | 1 | Using where |
+----+-------------+--------------+--------+--------------------------------------------------------------------+----------+---------+-----------------------------------------+--------+---------------------------------+
Why the first table in result is cl1_ and why mysql doesn't use key?
Because you used the keyword 'Explain', and because cl1_ is the alias you gave the table in your query.
I don't understand your question about the key.

Why won't MySQL use a reference index on the JOIN?

In the following example, MySQL fails to use to find a ref for the JOIN clause (or so it appears). Can anyone explain why?
mysql> explain SELECT 1
FROM `businesses`
INNER JOIN `categories`
ON (`businesses`.`id` = `categories`.`business_id`)
WHERE (`categories`.`category_id` IN (1321, 7304, 9189, 4736, 4737, 1322, 8554, 1323, 1324, 9459, 1325, 1326, 4738, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 8031, 8387)
AND `businesses`.`id` <= 170261
AND `businesses`.`id` >= 160262 ) ;
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
+----+-------------+-------------------------------------+-------+--------------------------+-------------+---------+------+-------+-
| 1 | SIMPLE | businesses | range | PRIMARY | PRIMARY | 4 | NULL | 20492 | Using where
| 1 | SIMPLE | categories | range | business_id,idx_category | business_id | 10 | NULL | 20584 | Using where; Using index
+----+-------------+-------------------------------------+-------+--------------------------+-------------+---------+------+-------+-
categories table:
| categories | CREATE TABLE `categories` (
`id` int(11) NOT NULL auto_increment,
`business_id` int(10) unsigned default NULL,
`category_id` int(10) unsigned default NULL,
`country_id` char(2) default NULL,
`state_id` int(10) unsigned default NULL,
`city_id` int(10) unsigned default NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `business_id` (`business_id`,`category_id`),
KEY `idx_category2` (`country_id`,`state_id`,`city_id`,`category_id`),
KEY `idx_category` (`category_id`)
) ENGINE=InnoDB AUTO_INCREMENT=13155275 DEFAULT CHARSET=latin1 |
Index info on categories:
+-------------------------------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------------------------------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| categories | 0 | PRIMARY | 1 | id | A | 13154781 | NULL | NULL | | BTREE | |
| categories | 0 | business_id | 1 | business_id | A | 13154781 | NULL | NULL | YES | BTREE | |
| categories | 0 | business_id | 2 | category_id | A | 13154781 | NULL | NULL | YES | BTREE | |
| categories | 1 | idx_category2 | 1 | country_id | A | 17 | NULL | NULL | YES | BTREE | |
| categories | 1 | idx_category2 | 2 | state_id | A | 17 | NULL | NULL | YES | BTREE | |
| categories | 1 | idx_category2 | 3 | city_id | A | 53913 | NULL | NULL | YES | BTREE | |
| categories | 1 | idx_category2 | 4 | category_id | A | 13154781 | NULL | NULL | YES | BTREE | |
| categories | 1 | idx_category | 1 | category_id | A | 51995 | NULL | NULL | YES | BTREE | |
+-------------------------------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
Maybe it's because you're not looking for all categories with that business_id, but further limit the categories like;
WHERE (`categories`.`category_id` IN (1321, 7304, 9189, etc)
The MySQL guide has an article on the range join type that might be relevant.