Why this sql query keeps showing me a syntax error - mysql

The syntax error showed at "as t3" in the following code.
Im trying to full outer join 2 tables, but since mysql does not have full join, im using union to union 2 left/right joined table.
To me, I can not find any syntax error what so ever, but it just wont work...
SELECT
name, f.author_nameauthor_id, c1, c2
FROM
(
SELECT
author_id, c1, c2
FROM
(
(SELECT
author_id, amount AS c1
FROM Author_Keyword_Count
WHERE keyword_id=19478) AS t1
LEFT OUTER JOIN
(SELECT
author_id, amount AS c2
FROM Author_Keyword_Count
WHERE keyword_id=33944) AS t2
ON author_id=author_id
)
UNION
(
(SELECT author_id, amount AS c1 FROM Author_Keyword_Count WHERE keyword_id=19478) AS t3
RIGHT OUTER JOIN
(SELECT author_id, amount AS c2 FROM Author_Keyword_Count WHERE keyword_id=33944) AS t4
ON author_id=author_id
)
) AS f
LEFT OUTER JOIN Author ON author_id=id;

Some observations included below...
SELECT name
, f.author_nameauthor_id
, c1
, c2
FROM
( SELECT author_id
, c1
, c2
FROM
( !-- <-- something missing here!?!
( SELECT author_id
, amount c1
FROM Author_Keyword_Count
WHERE keyword_id = 19478
) t1
LEFT
JOIN
( SELECT author_id
, amount c2
FROM Author_Keyword_Count
WHERE keyword_id = 33944
) t2
ON author_id = author_id !-- <-- which author id equals which other author id!?!?
)
UNION
( !-- <-- something missing here!?!?
( SELECT author_id
, amount c1
FROM Author_Keyword_Count
WHERE keyword_id = 19478
) t3
RIGHT
JOIN !-- for ease of conceptualising, consider restructuring your logic to use a LEFT JOIN instead of a RIGHT JOIN
( SELECT author_id
, amount c2
FROM Author_Keyword_Count
WHERE keyword_id = 33944
) t4
ON author_id = author_id !-- <-- which author id equals which other author id!?!?
)
) f
LEFT
JOIN Author
ON author_id = id; !-- <-- which author id equals which id!?!?
Conceptally, you've written (SELECT 'x') a JOIN (SELECT 'y') b which is (I think) invalid. You could instead write SELECT * FROM (SELECT 'x') a JOIN (SELECT 'y') b, but perhaps there's a more elegant way structuring this query - if only we knew what you were actually trying to do.

Related

I was trying to intersect to table but it throws an error that 'intersect' is not valid at this position expecting EOF, ';'

SELECT id
, name
, bonus
FROM table1 a
LEFT
JOIN table2 b
ON a.id = b.employee_id
intersect
SELECT id
, name
, bonus
FROM table1 a
RIGHT
JOIN table2 b
ON a.id = b.employee_id;
SELECT tab1.id,tab1.name,tab1.bonus (SELECT id
, name
, bonus
FROM table1 a
LEFT
JOIN table2 b
ON a.id = b.employee_id) as tab1
INNER JOIN
(SELECT id
, name
, bonus
FROM table1 a
RIGHT
JOIN table2 b
ON a.id = b.employee_id) as tab2 ON tab1.id=tab2.id;
You can try like this

join 3 tables if 3rd table does not have that value

Table 1
id , userid, eventid , name
table 2
eventid , zoneid , userid
table 3
eventid , userid, status
if all three table having the eventid means i dont want to select that record (i mean if table 3 have the eventid), else i need to select records
i tried my query
SELECT
*
FROM
`table1` c1
INNER JOIN `table2` c2 ON c2.eventid = c1.eventid
LEFT JOIN table3 c3 ON c3.eventid = c1.eventid
WHERE
c2.zoneid=2
AND c1.active='1'
GROUP BY
c1.eventid
Add a where clause where there is no c3:
SELECT *
FROM `table1` c1
INNER JOIN `table2` c2 ON c2.eventid = c1.eventid
LEFT JOIN table3 c3 ON c3.eventid = c1.eventid
WHERE c2.zoneid=2 AND c1.active='1'
AND c3.id IS NULL
group by c1.eventid
SELECT
*
FROM
`table1` c1
INNER JOIN `table2` c2 ON c2.eventid = c1.eventid
WHERE
c2.zoneid=2
AND c1.active='1'
AND NOT EXISTS (SELECT * FROM table3 c3 WHERE c3.eventid = c1.eventid)
GROUP BY
c1.eventid
Applying a WHERE-condition (like some of the other answers suggest) on a table that has been joined through a LEFT/RIGHT OUTER JOIN will actually make it a regular join.
The other examples that have been posted ask c1.eventid to equal c3.eventid, and c3.eventid to be NULL - good chance that the result will be not what you expect, depending on how the database treats c1.eventid = c3.eventid if both are NULL (I'd have to read up on that).
A Left join on the 3rd table and the condition WHERE C.eventid IS NULL should do the work.
SELECT *
FROM table1 A
INNER JOIN table2 B
ON A.eventid = B.eventid
LEFT OUTER JOIN table3 C
ON A.eventid = C.eventid
WHERE C.eventid IS NULL

MySQL: A weird query: select a field with many records

I have a table like this:
----------
id | name | tel | email
----------
1 john 0241 re#yah
2 0534 re#rra
3 435 fd#rar
4 geo 43435 re#eae
5 2347 ui#ear
6 678 re#yaya
I want to make a query like this:
SELECT tel, email FROM table WHERE name='geo'
and the output to be like that:
----------
tel | email
----------
43435 re#eae
2347 ui#ear
678 re#yaya
Thank you very much in advance
SELECT tel, email
FROM table1
JOIN (SELECT MAX(startid) startid,
IFNULL(MAX(endid), (SELECT MAX(id) FROM table1)) endid
FROM (SELECT id startid, NULL endid FROM table1 WHERE name = 'geo'
UNION
SELECT NULL, MIN(id)-1 FROM table1
WHERE name != ''
AND id > (SELECT id FROM table1 WHERE name = 'geo')) x) y
ON id BETWEEN startid AND endid
SQLFIDDLE
SELECT tel, name FROM
(SELECT id FROM table WHERE name = 'geo') a
LEFT JOIN table b ON
b.id = a.id
WHERE b.id >= a.id AND b.id < (SELECT id from table WHERE name > ''
ORDER BY ID ASC
LIMIT 1) c
Using user variables:-
SELECT tel, email
FROM
(
SELECT Sub1.id, Sub1.name, Sub1.tel, Sub1.email, #name:=IF(name IS NULL, #name, name) AS aName
FROM (SELECT * FROM geoname ORDER BY id) Sub1
CROSS JOIN (SELECT #name:="") Sub2
) Sub3
WHERE aName = 'geo'
As Barmar highlighted, this only works if the name field has NULL in it when empty rather than ''. If it needs to cope with blanks as well as NULL:-
SELECT tel, email
FROM
(
SELECT Sub1.id, Sub1.name, Sub1.tel, Sub1.email, #name:=IF(name IS NULL OR name = "", #name, name) AS aName
FROM (SELECT * FROM Table1 ORDER BY id) Sub1
CROSS JOIN (SELECT #name:="") Sub2
) Sub3
WHERE aName = 'geo'
Had a bit more of a play. Quite liked the solution by Barmar but had a play to see if I could simplify and remove a couple of subselects:-
SELECT a.*
FROM geoname a
INNER JOIN
(
SELECT a.id AS MinId, IFNULL(MIN(b.id), MAX(c.id)) AS MaxId
FROM geoname a
LEFT OUTER JOIN geoname b
ON a.id < b.id AND b.name IS NOT NULL
CROSS JOIN geoname c
WHERE a.name = 'geo'
GROUP BY a.id
) Sub1
ON a.id BETWEEN Sub1.MinId AND Sub1.MaxId
Seems marginally quicker and has a simpler explain.
Or to cope with blanks as well as NULLS
SELECT a.*
FROM geoname a
INNER JOIN
(
SELECT a.id AS MinId, IFNULL(MIN(b.id), MAX(c.id)) AS MaxId
FROM geoname a
LEFT OUTER JOIN geoname b
ON a.id < b.id AND b.name IS NOT NULL OR b.name = ''
CROSS JOIN geoname c
WHERE a.name = 'geo'
GROUP BY a.id
) Sub1
ON a.id BETWEEN Sub1.MinId AND Sub1.MaxId
Assuming that the id is increasing and the next entries without a name belong to that same one, it would be the easiest to update your table accordingly.
Here's how:
Test data:
/*
drop table yourTable;
CREATE TABLE yourTable
(`id` int, `name` varchar(40), `tel` int, `email` varchar(20))
;
INSERT INTO yourTable
(`id`, `name`, `tel`, `email`)
VALUES
(1, 'john', 0241, 're#yah'),
(2, NULL, 0534, 're#rra'),
(3, NULL, 435, 'fd#rar'),
(4, 'geo', 43435, 're#eae'),
(5, NULL, 2347, 'ui#ear'),
(6, NULL, 678, 're#yaya'),
(7, 'anything', 789, 'whatever')
;
#*/
UPDATE yourTable yt1 INNER JOIN (
SELECT
yt.*,
COALESCE(name, #prev) AS newName,
CASE WHEN name IS NOT NULL THEN #prev:=name END
FROM
yourTable yt
, (SELECT #prev:=NULL) v
ORDER BY id
) yt2 ON yt1.id = yt2.id
SET yt1.name = yt2.newName;
SELECT * FROM yourTable;
Result:
id name tel email
1 john 241 re#yah
2 john 534 re#rra
3 john 435 fd#rar
4 geo 43435 re#eae
5 geo 2347 ui#ear
6 geo 678 re#yaya
7 anything 789 whatever
Then your query should work fine.
SELECT i.id, i.tel, i.email
FROM
tableX AS t
JOIN
tableX AS i
ON i.id >= t.id
AND i.id < COALESCE(
( SELECT n.id
FROM tableX AS n
WHERE n.id > t.id
AND n.name <> ''
ORDER BY n.id ASC
LIMIT 1
), 2147483647)
WHERE
t.name = 'geo' ;
Tested at SQL-Fiddle-1 (thnx #Barmar)

MySQL COUNT of multiple left joins - optomization

I have a query that is getting counts from multiple tables by using a LEFT JOIN and subqueries. The idea is to get a count various activites a member has participated in.
The schema looks like this:
member
PK member_id
table1
PK tbl1_id
FK member_id
table2
PK tbl2_id
FK member_id
table3
PK tbl3_id
FK member_id
My query looks like this:
SELECT t1.num1,t2.num2,t3.num3
FROM member m
LEFT JOIN
(
SELECT member_id,COUNT(*) as num1
FROM table1
GROUP BY member_id
) t1 ON t1.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num2
FROM table2
GROUP BY member_id
) t2 ON t2.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num3
FROM table3
GROUP BY member_id
) t3 ON t3.member_id = m.member_id
WHERE m.member_id = 27
Where 27 is a test id. The actual query joins more than three tables and the query is run multiple times with the member_id being changed. The problem is this query runs pretty slow. I get the info I need but I am wondering if anyone could suggest a way to optimize this. Any advice is very much appreciated. Thanks much.
You should refactor your query. You can do this by reordering the way the query collects the data. How?
Apply the WHERE clause first
Apply JOINs last
Here is your original query:
SELECT t1.num1,t2.num2,t3.num3
FROM member m
LEFT JOIN
(
SELECT member_id,COUNT(*) as num1
FROM table1
GROUP BY member_id
) t1 ON t1.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num2
FROM table2
GROUP BY member_id
) t2 ON t2.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num3
FROM table3
GROUP BY member_id
) t3 ON t3.member_id = m.member_id
WHERE m.member_id = 27
Here is you new query
SELECT
IFNULL(t1.num1,0) num1,
IFNULL(t1.num2,0) num2,
IFNULL(t1.num3,0) num3
FROM
(
SELECT * FROM member m
WHERE member_id = 27
)
LEFT JOIN
(
SELECT member_id,COUNT(*) as num1
FROM table1
WHERE member_id = 27
GROUP BY member_id
) t1 ON t1.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num2
FROM table2
WHERE member_id = 27
GROUP BY member_id
) t2 ON t2.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num3
FROM table3
WHERE member_id = 27
GROUP BY member_id
) t3 ON t3.member_id = m.member_id
;
BTW I changed member m into SELECT * FROM member m WHERE member_id = 27 in case you need any information about member 27. I also added the IFNULL function to each result to produce 0 in case count is NULL.
You need to make absolutely sure
member_id is the primary key of the member table
member_id is indexed in table1, table2, and table3
Give it a Try !!!
Without knowing your schema and what you've done for indexes, one POSSIBLE way to make this faster is:
SELECT (select ifnull(count(*),0) from table1 where table1.member_id = m.id) as num1,
(select ifnull(count(*),0) from table2 where table2.member_id = m.id) as num2,
(select ifnull(count(*),0) from table3 where table3.member_id = m.id) as num3
from member m
WHERE m.member_id = 27
Now, this is a slightly risky recommendation, simply because I don't know anything about your DB or what else is running, or where the bottlenecks are.
In general, it would be a good idea to post an explain plan with your query to get a better answer.
SELECT num1, num2, count(*) as num3
FROM (
SELECT member_id, num1, count(*) as num2
FROM (
SELECT member_id, count(*) as num1
FROM member
LEFT JOIN table1 USING (member_id)
WHERE member_id = 27) as m1
LEFT JOIN table2 USING (member_id)) as m2
LEFT JOIN table3 USING (member_id);

sql query question

I have tables
table 1
id text
1 A
1 B
2 C
table 2
id text
1 x
1 f
2 y
2 z
I want to join them this way
1 A x
1 B f
2 C y
2 z
In other words i want to see all texts from table1 and table2 grouped by id, with no repeats.
Any ideas?
Update: as they say in comments, the logic is not clear, I'll try to explain.
I have current values in table_1 and deleted values in table_2.
Customer wants to see current values and deleted values in one table grouped by some id.
Simple solution to get something close to what you're looking for
SELECT t1.id, t1.text, t2.text
FROM tbl_1 t1
INNER JOIN tbl_2 t2
ON t1.id = t2.id
this will create output
1 A x
1 B x
2 C y
2 C z
Only different is now that the duplicated texts x and C should somehow removed.
Update
precondition: duplicates per id are either in tbl_1 or tbl_2 not both !
Joining a grouped select in addition to above simple solution will allow to create kind of "CASE-Filters" to get your desired output.
SELECT
t1.id,
CASE
WHEN t2.text = txt_i2 THEN t1.text
END AS txt_t1,
CASE
WHEN t1.text = txt_i1 THEN t2.text
END AS txt_t2
FROM (
SELECT
i1.id,
i1.text AS txt_i1,
i2.text AS txt_i2
FROM tbl_1 i1
INNER JOIN tbl_2 i2
ON i1.id = i2.id
GROUP BY id
) i
INNER JOIN tbl_1 t1
ON i.id = t1.id
INNER JOIN tbl_2 t2
ON t1.id = t2.id
You should create a view of the tbl_1-tbl_2-join to get more readable SQL:
CREATE OR REPLACE VIEW V_tbl_1_2 AS (
SELECT
t1.id,
t1.text AS txt_1,
t2.text AS txt_2
FROM tbl_1 t1
INNER JOIN tbl_2 t2
ON t1.id = t2.id
)
;
SELECT
t.id,
CASE
WHEN t.txt_2 = i.txt_2 THEN t.txt_1
END AS txt_t1,
CASE
WHEN t.txt_1 = i.txt_1 THEN t.txt_2
END AS txt_t2
FROM V_tbl_1_2 t
INNER JOIN (
SELECT *
FROM V_tbl_1_2
GROUP BY id
) i ON t.id = i.id
;
USE MYSQL VIEW OR JOIN
This works if you can have no more than two items per id in either table and if neither one has complete duplicates. (And I must also add that this can only work if MySQL is able to swallow this monster and not choke with it.)
SELECT
COALESCE (t1.id, t2.id) AS id,
t1.text AS text1,
t2.text AS text2
FROM (
SELECT
t.id,
t.text,
CASE t.text WHEN m.text THEN 1 ELSE 2 END AS rowid
FROM table_1 t
INNER JOIN (
SELECT id, MIN(text) AS text
FROM table_1
GROUP BY id
) m ON t.id = m.id
) t1
FULL JOIN (
SELECT
t.id,
t.text,
CASE t.text WHEN m.text THEN 1 ELSE 2 END AS rowid
FROM table_2 t
INNER JOIN (
SELECT id, MIN(text) AS text
FROM table_2
GROUP BY id
) m ON t.id = m.id
) t2
ON t1.id = t2.id AND t1.rowid = t2.rowid
ORDER BY COALESCE (t1.id, t2.id), COALESCE (t1.rowid, t2.rowid)