I have two tables t1, t2 and the following query:
SELECT t2.year,
Count(t1.id) AS count
FROM t1,
t2
WHERE t2.t1id = t1.id
AND t2.year IN ( 1995, 1996, 1997, 1998,
1999, 2000 )
GROUP BY t2.year
ORDER BY t1.year
Which results in:
+----------+--------+
| year | count |
+----------+--------+
| 1995 | 1 |
| 1998 | 3 |
| 1999 | 3 |
| 2000 | 28 |
+----------+--------+
And as you can see some years are missing. Is it possible to rewrite this query such that it results in?
+----------+--------+
| year | count |
+----------+--------+
| 1995 | 1 |
| 1996 | 0 |
| 1997 | 0 |
| 1998 | 3 |
| 1999 | 3 |
| 2000 | 28 |
+----------+--------+
I could use php and check which rows are missing to fill in the missing gaps, but that doesn't seem very efficient.. Any ideas?
edit
t1
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(128) | NO | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
t2
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| t1id | int(11) | NO | | NULL | |
| year | int(11) | NO | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
For example:
t1
+----------+---------+
| id | name |
+----------+---------+
| 1 | john |
| 2 | bob |
| .. | .. |
+----------+---------+
t2
+----------+---------+---------+
| id | t1id | year |
+----------+---------+---------+
| 100 | 1 | 1995 |
| 101 | 2 | 1998 |
| 103 | 3 | 1998 |
| .. | .. | .. |
+----------+---------+---------+
Where after the combination I end up with:
+----------+---------+
| id | year |
+----------+---------+
| 100 | 1995 |
| 101 | 1998 |
| 103 | 1998 |
| .. | .. |
+----------+---------+
SELECT t2.year,
IF(Count(t1.id) > 0, Count(t1.id), 0)
FROM t1,
t2
WHERE t2.t1id = t1.id
AND t2.year IN ( 1995, 1996, 1997, 1998,
1999, 2000 )
GROUP BY t2.year
ORDER BY t1.year
Without a source of all possible years that your query could cover you are going to have to use php to do this. One approach would could look something like this.
function getCountsForRange(\PDO $dbConn, $startYear, $endYear){
$ret = array_fill_keys(range($startYear, $endYear), 0);
$stmt = $dbConn->prepare("SELECT t2.year,Count(t1.id) AS count ".
"FROM t1,t2 ".
"WHERE t2.t1id = t1.id AND t2.year between ? and ? ".
"GROUP BY t2.year ORDER BY t1.year");
$stmt->execute([$startYear, $endYear]);
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)){
$ret[$row["year"]] = $row["count"];
}
return $ret;
}
create table yrCheat
( year int not null
);
create table t1
( -- forgive lack of PK
id int not null,
name varchar(128) not null
);
create table t2
( -- forgive lack of PK
id int not null,
t1id int not null,
year int not null
);
insert t1(id,name) values (100,'john'),(101,'bob'),(102,'sally');
insert t2(id,t1id,year) values (100,1,1995),(101,2,1998),(101,3,1998),(101,4,1998);
insert into yrCheat (year) values (1990),(1991),(1992),(1993),(1994),(1995),(1996),(1997),(1998),(1999),(2000);
-- etc
select yc.year,count(t1.id) as count
from yrCheat yc
left join t2
on t2.year=yc.year -- and yc.year in (1995,1996,1997,1998,1999,2000)
left join t1
on t1.id=t2.id
where yc.year in (1995,1996,1997,1998,1999,2000)
group by yc.year
order by yc.year
+------+-------+
| year | count |
+------+-------+
| 1995 | 1 |
| 1996 | 0 |
| 1997 | 0 |
| 1998 | 3 |
| 1999 | 0 |
| 2000 | 0 |
+------+-------+
6 rows in set (0.00 sec)
You will need to handle the empty rows pragmatically or in the query itself depending on the situation.
See:
MySQL GROUP BY and Fill Empty Rows
or
Populating query results with empty rows
For some ideas.
Related
So I normalize my database and it seems quite complicated for me to fetch or update records in tables.
I have 5 tables ( details, country, materials, vendor_countries, vendor_materials). Actually "details" is my main table.
country table have two column (id, name).
materials table also have two column(id, name).
details table have personnel information about vendors (name, email, phone, address).
A vendor could have multiple countries and materials so I made two more tables vendor_countries and vendor_materials and their column are (did,cid), (did,mid).
"did" is the id of each vendor coming from details table and cid,mid is the country id and material id coming from country and material table.
Now I want to fetch vendors along with their countries and materials.
here is my details table, vendor_countries and vendor_materials tables
so far I made a query which is shown below:
select dt.vendor,
dt.email,
dt.address,
c.country,
m.material,
c.country
from country c
inner join vendor_countries vc on (c.id = vc.cid)
right join details dt on (dt.id = vc.did)
left join vendor_materials vm on dt.id = vm.did
left join material m on vm.mid = m.id
and i am getting results like this:
which is not right it should be in 3 rows because "ali" vendor works in 3 countries and 3 materials. I am looking for some smart solution which also not slow down my page. Thanks in advance.
In the absence of any response regarding table schema I tried to re-create the tables based upon the descriptions above -prefixing each table with v_ so I could group the tables in this db and referencing did as vid ( vendor id ) and populating with what I believed to be the sample data from the question
mysql> describe v_country;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(50) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
mysql> describe v_details;
+---------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| vendor | varchar(50) | YES | | NULL | |
| email | varchar(50) | YES | | NULL | |
| phone | varchar(50) | YES | | NULL | |
| address | varchar(50) | YES | | NULL | |
+---------+------------------+------+-----+---------+----------------+
mysql> describe v_materials;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(50) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
mysql> describe v_vendor_materials;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| vid | int(10) unsigned | NO | MUL | 0 | |
| mid | int(10) unsigned | NO | MUL | 0 | |
+-------+------------------+------+-----+---------+----------------+
mysql> describe v_vendor_countries;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| vid | int(10) unsigned | NO | MUL | 0 | |
| mid | int(10) unsigned | NO | MUL | 0 | |
+-------+------------------+------+-----+---------+----------------+
mysql> select * from v_country;
+----+----------+
| id | name |
+----+----------+
| 1 | pakistan |
| 2 | India |
| 3 | Iran |
+----+----------+
mysql> select * from v_details;
+----+--------+------------------+---------------+-----------+
| id | vendor | email | phone | address |
+----+--------+------------------+---------------+-----------+
| 1 | harris | harris#gmail.com | 0141 236 4523 | nowhere |
| 2 | Boris | boris#gmail.com | 0141 451 7845 | somewhere |
| 3 | Doris | doris#gmail.com | 0141 353 7845 | anywhere |
+----+--------+------------------+---------------+-----------+
mysql> select * from v_materials;
+----+---------+
| id | name |
+----+---------+
| 1 | ceramic |
| 2 | iron |
| 3 | plastic |
+----+---------+
mysql> select * from v_vendor_materials;
+----+-----+-----+
| id | vid | mid |
+----+-----+-----+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
+----+-----+-----+
mysql> select * from v_vendor_countries;
+----+-----+-----+
| id | vid | mid |
+----+-----+-----+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
+----+-----+-----+
mysql> select * from v_details d
left outer join v_vendor_materials vm on vm.vid=d.id
left outer join v_vendor_countries vc on vc.vid=d.id
left outer join v_materials m on m.id=vm.id
left outer join v_country c on c.id=vc.id;
+----+--------+------------------+---------------+-----------+------+------+------+------+------+------+------+---------+------+----------+
| id | vendor | email | phone | address | id | vid | mid | id | vid | mid | id | name | id | name |
+----+--------+------------------+---------------+-----------+------+------+------+------+------+------+------+---------+------+----------+
| 1 | harris | harris#gmail.com | 0141 236 4523 | nowhere | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ceramic | 1 | pakistan |
| 2 | Boris | boris#gmail.com | 0141 451 7845 | somewhere | 2 | 2 | 2 | 2 | 2 | 2 | 2 | iron | 2 | India |
| 3 | Doris | doris#gmail.com | 0141 353 7845 | anywhere | 3 | 3 | 3 | 3 | 3 | 3 | 3 | plastic | 3 | Iran |
+----+--------+------------------+---------------+-----------+------+------+------+------+------+------+------+---------+------+----------+
or, a more selective query
select
d.`id` as `vid`,
d.`vendor`,
d.`email`,
d.`phone`,
d.`address`,
m.`name` as `material`,
c.`name` as `country`
from v_details d
left outer join v_vendor_materials vm on vm.vid=d.id
left outer join v_vendor_countries vc on vc.vid=d.id
left outer join v_materials m on m.id=vm.id
left outer join v_country c on c.id=vc.id;
+-----+--------+------------------+---------------+-----------+----------+----------+
| vid | vendor | email | phone | address | material | country |
+-----+--------+------------------+---------------+-----------+----------+----------+
| 1 | harris | harris#gmail.com | 0141 236 4523 | nowhere | ceramic | pakistan |
| 2 | Boris | boris#gmail.com | 0141 451 7845 | somewhere | iron | India |
| 3 | Doris | doris#gmail.com | 0141 353 7845 | anywhere | plastic | Iran |
+-----+--------+------------------+---------------+-----------+----------+----------+
table milestoneeventI have three tables file and milestone event. I want to count milestones but by Company.
For example, if I want to count number of last milestone added for the milestone id=1, I do this:
select count('id') as st
from (
select idfile,
max(idmilestone) as max_idmilestone
from milestoneevent
group by idfile)
d where max_idmilestone =1
my problem is how to count them but for each company in table file I have column company. See the picture for more details
Statement should look like this
SELECT d.Comp,count(*),d.max_idmilestone FROM (
SELECT Comp, max(idmilestone) as max_idmilestone, count(idmilestone) as number FROM milestoneevent
INNER JOIN file ON file.id = idfile
GROUP BY idfile, Comp
) d GROUP BY d.max_idmilestone, d.Comp
In the subquery it give you the max(idmilestone) for every company but only if one milestone exists for a idfile, than count how many a max_idmilestone is occuring.
The Result of my test is
+-----------+----------+---+
| Comp | count(*) | |
+-----------+----------+---+
| Microsoft | 5 | 1 |
| Oracle | 1 | 1 |
| Microsoft | 2 | 2 |
| Oracle | 1 | 2 |
+-----------+----------+---+
**Query for Company or milestoneid
If you want to query for Company or max_idmilestone just do this
SELECT d.Comp,count(*),d.max_idmilestone FROM (
SELECT Comp, max(idmilestone) as max_idmilestone, count(idmilestone) as number FROM milestoneevent
INNER JOIN file ON file.id = idfile
WHERE Comp = "Microsoft"
GROUP BY idfile, Comp
) d
WHERE d.max_idmilestone = 1
GROUP BY d.max_idmilestone, d.Comp
Output
+-----------+----------+---+
| Comp | count(*) | |
+-----------+----------+---+
| Microsoft | 5 | 1 |
+-----------+----------+---+
For My Test I used the following structure. Skipped some columns which are not necessary for the test
CREATE TABLE `milestoneevent` (
`id` INT(22) NOT NULL auto_increment,
`idfile` INT(64) NOT NULL,
`idmilestone` INT(64) NOT NULL,
`company` VARCHAR(64) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `file` (
`id` int(22) NOT NULL AUTO_INCREMENT,
`Comp` varchar(64) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
Data of the test
+----+--------+-------------+
| id | idfile | idmilestone |
+----+--------+-------------+
| 1 | 1 | 1 |
| 2 | 10 | 1 |
| 3 | 11 | 1 |
| 4 | 12 | 1 |
| 5 | 13 | 1 |
| 6 | 14 | 1 |
| 7 | 15 | 1 |
| 8 | 16 | 2 |
| 9 | 14 | 2 |
| 10 | 18 | 2 |
+----+--------+-------------+
+----+-----------+
| id | Comp |
+----+-----------+
| 1 | Microsoft |
| 10 | Microsoft |
| 11 | Microsoft |
| 12 | Microsoft |
| 13 | Microsoft |
| 14 | Microsoft |
| 15 | Oracle |
| 16 | Oracle |
| 18 | Microsoft |
+----+-----------+
I have two tables
table A (result a view from some table) :
Query from table A :
SELECT view_person_schedule., view_history_absen., TIMEDIFF(time_in,schedule_time_in) AS late, TIMEDIFF(schedule_time_out,time_out) as overtime FROM person JOIN view_history_absen ON view_history_absen.ID = view_person_schedule.ID
table A :
ID | dates | time_in | time_out |
1 | 2014-06-01 | 07:00 | ........ |
1 | 2014-06-02 | 08:00 | ........ |
1 | 2014-06-03 | 08:10 | ........ |
1 | 2014-06-04 | ..... | ........ |
1 | 2014-06-05 | ..... | ........ |
1 | 2014-06-10 | ..... | ........ |
1 | 2014-06-14 | ..... | ........ |
table B :
ID | dates_exc | information |
1 | 2014-06-06 | NULL |
1 | 2014-06-07 | NULL |
1 | 2014-06-08 | NULL |
1 | 2014-06-09 | NULL |
1 | 2014-06-11 | SICK |
1 | 2014-06-12 | SICK |
1 | 2014-06-13 | SICK |
My question is : how to make result data to be like this below :
ID | dates | time_in | time_out |
1 | 2014-06-01 | 07:00 | ........ |
1 | 2014-06-02 | 08:00 | ........ |
1 | 2014-06-03 | 08:10 | ........ |
1 | 2014-06-04 | ..... | ........ |
1 | 2014-06-05 | ..... | ........ |
1 | 2014-06-06 | NULL | ........ |
1 | 2014-06-07 | NULL | ........ |
1 | 2014-06-08 | NULL | ........ |
1 | 2014-06-09 | NULL | ........ |
1 | 2014-06-10 | ..... | ........ |
1 | 2014-06-11 | SICK | ........ |
1 | 2014-06-12 | SICK | ........ |
1 | 2014-06-13 | SICK | ........ |
1 | 2014-06-14 | ..... | ........ |
Please anyone help me.
Assuming there are no overlapping dates in the two tables, or you want both rows in the result when there are, use a UNION:
SELECT id, dates, time_in, time_out
FROM TableA
UNION
SELECT id, dates_exc, information, NULL
FROM TableB
If Table B should take precedence when there's overlap:
SELECT dates.id, dates.dates, IFNULL(b.information, a.time_in) AS time_in, a.time_out
FROM (SELECT id, dates
FROM tableA
UNION DISTINCT
SELECT id, dates
FROM tableB) AS dates
LEFT JOIN tableB AS b ON dates.id = b.id AND dates.dates = b.dates
LEFT JOIN tableA AS a ON dates.id = a.id AND dates.dates = a.dates
I have this table that i use to query by grouping via station_id.
+------------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+---------------+------+-----+---------+-------+
| id | varchar(50) | NO | PRI | NULL | |
| station_id | tinyint(3) | NO | | NULL | |
| game_type_id | smallint(1) | NO | MUL | NULL | |
| price | decimal(10,2) | YES | | 0.00 | |
| date_created | datetime | YES | MUL | NULL | |
| bet_no1 | tinyint(2) | YES | | 0 | |
| bet_no2 | tinyint(2) | YES | | 0 | |
+------------------+---------------+------+-----+---------+-------+
Here is the query i use to display it on a table using GROUP BY station_id
SELECT station_id,
COUNT(*) as bet_counts,
FORMAT(SUM(price),2) as gross
FROM bets
WHERE bet_void=0
AND date_created >= '2013-02-12 00:00:00'
AND date_created < '2013-02-23 00:00:00'
GROUP BY station_id
The query will give me.
+------------+------------+-------+
| station_id | bet_counts | gross |
+------------+------------+-------+
| 1 | 14 | 16.00 |
| 2 | 5 | 5.00 |
| 7 | 11 | 11.00 |
+------------+------------+-------+
But i also have another query that counts each specific bets( game_type_id ) from each station_id. I usually query this inside the a looping statement.
SELECT COUNT(*) as count
FROM bets
WHERE game_type_id = 1
AND station_id = {station_id from first query}
AND date_created >= '2013-02-12 00:00:00'
AND date_created < '2013-02-23 00:00:00'
My question is, how can i make this in one query and still use the GROUP BY station_id and also get the count of bets on each game_type_id? Something like this result.
+------------+------------+-------+-------------------------+-------------------------+
| station_id | bet_counts | gross | count_of_game_type_id_1 | count_of_game_type_id_2 |
+------------+------------+-------+-------------------------+-------------------------+
| 1 | 14 | 16.00 | 10 | 4 |
| 2 | 5 | 5.00 | 3 | 2 |
| 7 | 11 | 11.00 | 11 | 0 |
+------------+------------+-------+-------------------------+-------------------------+
You can do this by joining the results together. However, the logic in the two queries is very similar, so you can combine them into a single aggregation query:
SELECT station_id,sum(case when bet_void = 0 then 1 else 0 end) as bet_counts,
FORMAT(SUM(case when bet_void = 0 then price else 0 end),2) as gross,
sum(case when game_type_id = 1 then 1 else 0 end) as count
FROM bets b
where date_created >= '2013-02-12 00:00:00' AND date_created < '2013-02-23 00:00:00'
GROUP BY station_id
I have this query
SELECT
products_list.id_cat_unique,
products_categories_list.*,
COUNT(products_list.id_cat_unique) as counter
FROM products_categories_ids
LEFT JOIN products_list
ON products_categories_ids.id_cat_unique = products_list.id_cat_unique
LEFT JOIN products_categories_list
ON products_categories_list.id_cat_unique = products_categories_ids.id_cat_unique
GROUP BY products_categories_list.name_cat
ORDER BY products_categories_list.name_cat ASC
This is complicated to explain without having the tables on your screen but I'll try
what I want is count all the rows from products_list that can be associated with max two rows per id_cat_unique (contained in products_categories_list) that are English or Italian. This two items each could have infinite id_products in products_list of course.
I want the result to be grouped by products_categories_list.name_cat and by the language.
What I get with this query is categories grouped by name/unique id which is correct, the problem is that the counter value for both English and Italian turns out as the sum of all the products associated with one id_cat_unique regardless of the language. So if I have 12 rows from one category in English and 3 for the same category in Spanish I get 15 as counter for both the languages.
EDIT ADDING TABLES STRUCTURES
products_list
+-------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+----------------+
| id_product | int(11) | NO | PRI | NULL | auto_increment |
| id_product_unique | int(5) | NO | | NULL | |
| lang | varchar(2) | NO | | NULL | |
| name_product | varchar(200) | NO | | NULL | |
| desc_product | text | NO | | NULL | |
| id_cat_unique | int(2) | NO | | NULL | |
| status | int(1) | NO | | NULL | |
+-------------------+--------------+------+-----+---------+----------------+
12 rows in set (0.00 sec)
products_categories_ids
+---------------+--------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------+------+-----+---------+----------------+
| id_cat_unique | int(5) | NO | PRI | NULL | auto_increment |
+---------------+--------+------+-----+---------+----------------+
1 row in set (0.00 sec)
products_categories_list
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id_cat | int(5) | NO | PRI | NULL | auto_increment |
| id_cat_unique | int(2) | NO | | NULL | |
| lang | varchar(2) | NO | | NULL | |
| name_cat | varchar(500) | NO | | NULL | |
| date_created | int(11) | NO | | NULL | |
| date_modified | int(11) | NO | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)
result from query
| id_cat_unique | id_cat | id_cat_unique | lang | name_cat | date_created | date_modified | counter |
+---------------+--------+---------------+------+--------------------------------+--------------+---------------+---------+
| 1 | 18 | 1 | it | Carne di suino | 1308267538 | 1308267538 | 6 |
| 14 | 21 | 14 | it | Guanciali | 1308777322 | 1308777322 | 2 |
| 3 | 20 | 3 | it | Pollo a pezzi | 1308267892 | 1308267892 | 2 |
| 1 | 22 | 1 | en | Pork meat | 1308267538 | 1312383232 | 6 |
| 14 | 23 | 14 | en | Sheeps | 1308777322 | 1312383220 | 2 |
| 2 | 19 | 2 | it | That's a "test" | 1308267538 | 1308267538 | 7 |
+---------------+--------+---------------+------+--------------------------------+--------------+---------------+---------+
6 rows in set (0.00 sec)
"Pork meat" and "Carne di Suino" have respectively 1 and 5 products (from the same category but different language, i wanna group the counting by language too) instead it shows 6 for both
NEW question
I'd like to use this query for many purposes without using different things, so accordingly if I want to retrieve the categories with ONE language I'd add one where clause
select pcl.*,
(select count(*) from products_list pl
where pcl.id_cat_unique = pl.id_cat_unique
and pcl.lang = pl.lang) as counter
from products_categories_list pcl
where products_list.lang = 'en' <- added
ORDER BY pcl.name_cat ASC
I get Unknown column 'products_list.lang' in 'where clause'. Why?
I THINK this will work, if not, it's going to be close, let me know what you get, and I can modify it. I've modified the query around. Would this work?
select pcl.*,
(select count(*) from products_list pl
where pcl.id_cat_unique = pl.id_cat_unique
and pcl.lang = pl.lang) as counter
from products_categories_list pcl
ORDER BY pcl.name_cat ASC
The PCL and PL are just aliases for the tables, so I didn't have to always write out products_categories_list and products_list. You specify the alias in the from part of the statement, so from products_list pl allows you to refer to products_list as pl in the rest of the query.
The idea behind this is that you have a unique row for each products_categories_list and you want a count of a secondary table. This could have been done by group by or by a sub query. I put the correlated subquery in to count the number of rows in products_list that matched the products_categories_list and language, since you are getting all the columns out of the products_categories_list. The correlated subquery allows you to get a single value (count(*)) from a nested query.
Probably this: add DISTINCT
COUNT(DISTINCT products_list.id_cat_unique) as counter
This will ignore duplicate, so the 12+3 via the JOIN becomes 1+1