DISTINCT keyword not working in mysql query - mysql

I have ran into a problem that my mysql query is not working as expected. I am joining 3 tables using union and from the result i want to ignore the repeating words. For that I have used DISTINCT keyword. But it is not working as expected.
My query is,
SELECT DISTINCT(catnam), sub2id
FROM tbl_first_page_products f INNER JOIN subcategory_level2 s
ON f.brand_id = s.sub2id
WHERE f.title_cat = 'men'
UNION
SELECT DISTINCT(catnam), sub2id
FROM tbl_third_page_products f INNER JOIN subcategory_level2 s
ON f.brand_id = s.sub2id
WHERE f.title_cat = 'men'
UNION
SELECT DISTINCT(catnam), sub2id
FROM tbl_fourth_page_products f INNER JOIN subcategory_level2 s
ON f.brand_id = s.sub2id
WHERE f.title_cat = 'men'
And my result is,
catnam sub2id
------ ------
Levi's 4
United 1
Reebok 130
Jack 18
Proline 77
Levi's 161
Arrow 284
In the above result Levi's is repeating. How to ignore this. I need only one Levi's. Is there any way to avoid this. I am stuck in here.

MySQL DISTINCT with multiple columns
You can use the DISTINCT clause with more than one column. In this case, MySQL uses the combination of all columns to determine the uniqueness of the row in the result set.
http://www.mysqltutorial.org/mysql-distinct.aspx
if you want solve your problem, you can use group_concat() function then you group by catnam for all union queries :
SELECT name ,GROUP_CONCAT(id)
FROM your_table
GROUP BY name ;
so your query can be:
SELECT distinct(catnam) as catnam, GROUP_CONCAT(sub2id )
FROM tbl_first_page_products f INNER JOIN subcategory_level2 s
ON f.brand_id = s.sub2id
WHERE f.title_cat = 'men'
UNION
SELECT distinct(catnam) as catnam, GROUP_CONCAT(sub2id )
FROM tbl_third_page_products f INNER JOIN subcategory_level2 s
ON f.brand_id = s.sub2id
WHERE f.title_cat = 'men'
UNION
SELECT distinct(catnam) as catnam, GROUP_CONCAT(sub2id )
FROM tbl_fourth_page_products f INNER JOIN subcategory_level2 s
ON f.brand_id = s.sub2id
WHERE f.title_cat = 'men'
group by catnam

I'd try:
SELECT n, GROUP_CONCAT(sub2id )
FROM
(
SELECT catnam n, sub2id
...
UNION
SELECT catnam, sub2id
...
)
GROUP BY n

Related

How can those two SQL statements be combined into one?

I wrote and would like to combine these 2 sql, one is based on results of another. I checked this post, but looks like its not results based. How could I achieve it ?
First sql:
SELECT
`potential`.*,
`customer`.`ID` as 'FID_customer'
FROM
`os_potential` as `potential`,
`os_customer` as `customer`
WHERE `potential`.`FID_author` = :randomID
AND `potential`.`converted` = 1
AND `potential`.`street` = `customer`.`street`
AND `potential`.`zip` = `customer`.`zip`
AND `potential`.`city` = `customer`.`city`;
Second sql:
SELECT
sum(`order`.`price_customer`) as 'Summe'
FROM
`os_order` as `order`,
`RESUTS_FROM_PREVIOUS_SQL_STATEMENT` as `results`
WHERE `order`.`FID_status` = 10
AND `results`.`FID_customer` = `order`.`FID_customer`;
I would like to get everything from first sql + the 'Summe' from second sql.
TABLES
1.Potentials:
+----+------------+-----------+--------+-----+------+
| ID | FID_author | converted | street | zip | city |
+----+------------+-----------+--------+-----+------+
2.Customers:
+----+--------+-----+------+
| ID | street | zip | city |
+----+--------+-----+------+
3.Orders:
+----+--------------+----------------+
| ID | FID_customer | price_customer |
+----+--------------+----------------+
SELECT p.*
, c.ID FID_customer
, o.summe
FROM os_potential p
JOIN os_customer c
ON c.street = p.street
AND c.zip = p.zip
AND c.city = p.city
JOIN
( SELECT FID_customer
, SUM(price_customer) Summe
FROM os_order
WHERE FID_status = 10
GROUP
BY FID_customer
) o
ON o.FID_customer = c.ID
WHERE p.FID_author = :randomID
AND p.converted = 1
;
You would just write a single query like this:
SELECT sum(o.price_customer) as Summe
FROM os_order o JOIN
os_potential p JOIN
os_customer c
ON p.street = c.street AND p.zip = c.zip AND p.city = c.city JOIN
os_order o2
ON o2.FID_customer = c.FID_customer
WHERE p.FID_author = :randomID AND p.converted = 1 AND
o2.FID_status = 10 ;
Notes:
Never use commas in the FROM clause. Always use explicit JOIN syntax with conditions in an ON clause.
Table aliases are easier to follow when they are short. Abbreviations for the table names is commonly used.
Backticks are only necessary when the table/column name needs to be escaped. Yours don't need to be escaped.
If the 1st query return 1 record per customer, then just simply join the 3 tables, keep the sum and use the group by clause:
SELECT
`potential`.*,
`customer`.`ID` as 'FID_customer',
sum(`order`.`price_customer`) as Summe
FROM
`os_potential` as `potential`
INNER JOIN
`os_customer` as `customer`
ON `potential`.`street` = `customer`.`street`
AND `potential`.`zip` = `customer`.`zip`
AND `potential`.`city` = `customer`.`city`
LEFT JOIN
`os_order` as `order`
ON `results`.`FID_customer` = `order`.`FID_customer`
AND `order`.`FID_status` = 10
WHERE `potential`.`FID_author` = :randomID
AND `potential`.`converted` = 1
GROUP BY `customer`.`ID`, <list all fields from potential table>
If the 1st query may return multiple records per customer, then you need to do the summing in a subquery:
SELECT
`potential`.*,
`customer`.`ID` as 'FID_customer',
`order`.Summe
FROM
`os_potential` as `potential`
INNER JOIN
`os_customer` as `customer`
ON `potential`.`street` = `customer`.`street`
AND `potential`.`zip` = `customer`.`zip`
AND `potential`.`city` = `customer`.`city`
LEFT JOIN
(SELECT FID_customer, sum(price_customer) as Summe
FROM `os_order`
WHERE FID_status=10
GROUP BY FID_customer
) as `order`
ON `results`.`FID_customer` = `order`.`FID_customer`
WHERE `potential`.`FID_author` = :randomID
AND `potential`.`converted` = 1
I think you should use a subselect, but be careful with the number of results, it's not the best for performance.
You can do something like this:
SELECT n1, n2, (select count(1) from whatever_table) as n3, n4 from whatever_table
note that the subselect must return just 1 result, in other case you'll have an error

How can I optimize this mysql query

I would like to ask, how can I optimize this query:
select
h.jmeno hrac,
n1.url hrac_url,
t.nazev tym,
n2.url tym_url,
ss.pocet_zapasu zapasy,
ss.pocet_minut minuty,
s.celkem_golu goly,
s.zk,
s.ck
from
hraci h
left join
(
select
hrac_id,
tym_id,
count(minut_celkem) pocet_zapasu,
sum(minut_celkem) pocet_minut
from
statistiky_stridani ss
join
zapasy z
on z.id = ss.zapas_id
join
souteze s
on s.id = z.soutez_id
join
souteze_nazev sn
on sn.id = s.soutez_id
where
s.rocnik_id = 2
group by
hrac_id
) ss on ss.hrac_id = h.id
left join
(
select
hrac_id,
tym_id,
sum(typ_id = 1 or typ_id = 3) as celkem_golu,
sum(typ_id = 4) as zk,
sum(typ_id = 5) as ck
from
statistiky st
join
zapasy z
on z.id = st.zapas_id
join
souteze s
on s.id = z.soutez_id
join
souteze_nazev sn
on sn.id = s.soutez_id
where
s.rocnik_id = 2
group by
hrac_id
) s on s.hrac_id = h.id
join
navigace n1
on n1.id = h.nav_id
join
tymy t
on t.id = ss.tym_id
join
navigace n2
on n2.id = t.nav_id
order by
s.celkem_golu desc
limit
10
Because query takes about 1,5 - 2 seconds. For example, table statistiky_stridani has about 500 000 rows and statistiky about 250 000 rows.
This returns EXPLAIN:
Thank you for your help
Don't use LEFT JOIN instead of JOIN unless you really need the empty rows.
Try to reformulate because JOIN ( SELECT ... ) JOIN ( SELECT ... ) optimizes poorly.
Please do not use the same alias (s) for two different tables; it confuses the reader.
Add the composite index INDEX(rocnik_id, soutez_id) to souteze.
LEFT JOIN ... JOIN ... -- Please add parentheses to show whether the JOIN should be before doing the LEFT JOIN or after:
either
FROM ...
LEFT JOIN ( ... JOIN ... )
or
FROM ( ... LEFT JOIN ... )
JOIN ...
It may make a big difference in how the Optimizer performs the query, which may change the speed.
There may be more suggestions; work through those and ask again (if it is still "too slow").

WHERE [1 of these values] IN [1 of these values]

I have the following query :
SELECT A.id FROM logsen_alertes A
WHERE
( SELECT LA2.type_colocation_id
FROM logsen_liaisons_annonces_types_colocations LA2
WHERE LA2.annonce_id = 25 AND LA2.annonce_type = 4
)
IN
( SELECT L4.souhait
FROM logsen_liaisons_alertes_souhaits L4
WHERE L4.alerte_id = A.id
)
This query works well when my first subquery returns only 1 value, because that's how works IN(), looking for 1 unique value in a set of values. When my 1st subquery returns 2 or more values, MySQL returns me "Subquery returns more than 1 row". How can I make my query works when the first subquery returns several values ? Something like "WHERE [any of these values] i found in [ny of these values]" ?
Try:
SELECT DISTINCT A.id FROM logsen_alertes A
JOIN logsen_liaisons_alertes_souhaits L4 ON L4.alerte_id = A.id
JOIN logsen_liaisons_annonces_types_colocations LA2
ON LA2.type_colocation_id = L4.souhait AND LA2.annonce_id = 25 AND LA2.annonce_type = 4
Try this:
SELECT
A.id
FROM
logsen_alertes A
INNER JOIN logsen_liaisons_alertes_souhaits L4
ON L4.alerte_id = A.id
INNER JOIN logsen_liaisons_annonces_types_colocations LA2
ON LA2.type_colocation_id = L4.souhait
WHERE
LA2.annonce_id = 25 AND LA2.annonce_type = 4
SELECT DISTINCT A.id FROM logsen_alertes AS A
INNER JOIN logsen_liaisons_alertes_souhaits AS L4
ON (L4.alerte_id = A.id)
INNER JOIN logsen_liaisons_annonces_types_colocations AS LA2
ON (LA2.type_colocation_id = L4.souhait)
WHERE LA2.annonce_id = 25 AND LA2.annonce_type = 4
Should work

combining multiple sql queries together

I have multiple table for a project (sessions , charges and payments)
To get the sessions i'm doing the following :
SELECT
sess.file_id, SUM(sess.rate * sess.length) AS total
FROM
sess
WHERE sess.sessionDone = 1
GROUP BY sess.file_id
This will return the amount that a specific student should pay
I also have another table "charges"
SELECT
file_charges.file_id, SUM(file_charges.price) AS total_charges
FROM
file_charges
GROUP BY file_charges.file_id
And finally the payment query :
SELECT
file_payments.file_id, SUM(file_payments.paymentAmount) AS total_payment
FROM
file_payments
GROUP BY file_payments.file_id
Can i combine those 3 in a way to have :
Total = Payments - (Session + Charges)
Note that it could be negative so i could have file_id that exists in session , charges but not in payments and i could have a payment without sessions or charges ...
Edit : http://sqlfiddle.com/#!2/a90d9
One issue that needs to be addressed is whether one of these queries can be the "driver", in cases where we don't have rows for a given file_id returned by one or more of the queries. (e.g. there might be rows from sess, but none from file_payments. If we want to be sure to include every possible file_id that appears in any of the queries, we can get a list of all possible file_id with a query like this:
SELECT ss.file_id FROM sess ss
UNION
SELECT fc.file_id FROM file_charges fc
UNION
SELECT fp.file_id FROM file_payments fp
(NOTE: The UNION operator will remove any duplicates)
To get the specified resultset, we can use that query, along with "left joins" of the other three original queries. The outline of the query will be:
SELECT a.file_id, p.total_payment - ( s.total + c.total_charges)
FROM a
LEFT JOIN s ON s.file_id = a.file_id
LEFT JOIN c ON c.file_id = a.file_id
LEFT JOIN p ON p.file_id = a.file_id
ORDER BY a.file_id
In that statement a is a standin for the query that gets the set of all file_id values (as shown above). The s, c and p are standins for your three original queries, on sess, file_charges and file_payments, respectively.
If any of the file_id values is "missing" from any of the queries, we are going to need to substitute a zero for the missing value. We can use the IFNULL function to handle that for us.
This query should return the specified resultset:
SELECT a.file_id
, IFNULL(p.total_payment,0) - ( IFNULL(s.total,0) + IFNULL(c.total_charges,0)) AS t
FROM ( -- all possible values of file_id
SELECT ss.file_id FROM sess ss
UNION
SELECT fc.file_id FROM file_charges fc
UNION
SELECT fp.file_id FROM file_payments fp
) a
LEFT
JOIN ( -- the amount that a specific student should pay
SELECT sess.file_id, SUM(sess.rate * sess.length) AS total
FROM sess
WHERE sess.sessionDone = 1
GROUP BY sess.file_id
) s
ON s.file_id = a.file_id
LEFT
JOIN ( -- charges
SELECT file_charges.file_id, SUM(file_charges.price) AS total_charges
FROM file_charges
GROUP BY file_charges.file_id
) c
ON c.file_id = a.file_id
LEFT
JOIN ( -- payments
SELECT file_payments.file_id, SUM(file_payments.paymentAmount) AS total_payment
FROM file_payments
GROUP BY file_payments.file_id
) p
ON p.file_id = a.file_id
ORDER BY a.file_id
(The EXPLAIN for this query is not going to be pretty, with four derived tables. On really large sets, performance may be horrendous. But the resultset returned should meet the specification.)
Beware of queries that JOIN all three tables together... that will likely give incorrect results when there are (for example) two (or more) rows for the same file_id in the file_payment table.
There are other approaches to getting an equivalent result set, but the query above answers the question: "how can i get the results of these queries joined together into a total".
Using correlated subqueries
Here's another approach, using correlated subqueries in the SELECT list...
SELECT a.file_id
, IFNULL( ( SELECT SUM(file_payments.paymentAmount) FROM file_payments
WHERE file_payments.file_id = a.file_id )
,0)
- ( IFNULL( ( SELECT SUM(sess.rate * sess.length) FROM sess
WHERE sess.file_id = a.file_id )
,0)
+ IFNULL( ( SELECT SUM(file_charges.price) FROM file_charges
WHERE file_charges.file_id = a.file_id )
,0)
) AS tot
FROM ( -- all file_id values
SELECT ss.file_id FROM sess ss
UNION
SELECT fc.file_id FROM file_charges fc
UNION
SELECT fp.file_id FROM file_payments fp
) a
ORDER BY a.file_id
try this
SELECT sess.file_id, SUM(file_payments.paymentAmount) - (SUM(sess.rate * sess.length)+SUM(file_charges.price)) as total_payment FROM sess , file_charges , file_payments
WHERE sess.sessionDone = 1
GROUP BY total_payment
EDIT.
SELECT a.file_id
, IFNULL(p.total_payment,0) - ( IFNULL(s.total,0) + IFNULL(c.total_charges,0)) AS tot
FROM (
SELECT ss.file_id FROM sess ss
UNION
SELECT fc.file_id FROM file_charges fc
UNION
SELECT fp.file_id FROM file_payments fp
) a
LEFT JOIN (
SELECT sess.file_id, SUM(sess.rate * sess.length) AS total
FROM sess
WHERE sess.sessionDone = 1
GROUP BY sess.file_id
) s
ON s.file_id = a.file_id
LEFT JOIN (
SELECT file_charges.file_id, SUM(file_charges.price) AS total_charges
FROM file_charges
GROUP BY file_charges.file_id
) c
ON c.file_id = a.file_id
LEFT JOIN (
SELECT file_payments.file_id, SUM(file_payments.paymentAmount) AS total_payment
FROM file_payments
GROUP BY file_payments.file_id
) p
ON p.file_id = a.file_id
ORDER BY a.file_id
DEMO HERE

SQL Multi table select query

http://i.stack.imgur.com/mbUTI.jpg
I want to Do a multi select in one query where one table has data from many tables.
i have four tables to combine it into a single output.
here is a image of my table.
i want to select all and don't want other data from other table just main table with name of all other tables
have tried following but its not working.
select * from project_content
left Join project_master on project_master.id = project_content.p_id
left Join project_content_menu on project_content_menu.type_id = project_content.p_c_id
left Join project_menu_master on project_menu_master.id = project_content.m_id
select * from project_content
left Join project_master on project_master.id = project_content.p_id
left Join project_content_menu on project_content_menu.type_id = project_content.p_c_id
left Join project_menu_master on project_menu_master.id = project_content.m_id
select distinct(*) from project_content
left OUTER Join project_master on project_master.id = project_content.p_id
left OUTER Join project_content_menu on project_content_menu.type_id = project_content.p_c_id
left OUTER Join project_menu_master on project_menu_master.id = project_content.m_id
select * from project_content ,project_master,project_content_menu,project_menu_master
where project_master.id = project_content.p_id and project_content_menu.type_id = project_content.p_c_id and project_menu_master.id = project_content.m_id
select pc.id as id , pm.name as pname , pmm.name as menuname , pcm.name as contentname , pc.name as name
from
project_content as pc,
project_master as pm,
project_content_menu as pcm,
project_menu_master as pmm
where
pm.id = pc.p_id
and
pcm.type_id = pc.m_id
and
pmm.id = pc.p_c_id
If I undesrtood you correctly, you want the data just from the main table, but with names instead of foreign keys from other tables? If so, then:
SELECT pc.id, pm.name, pcm.name, pmm.name, pc.name, pc.desc, pc.thumb, pc.src, pc.status
FROM project_content AS pc
LEFT JOIN project_master AS pm ON pm.id = pc.p_id
LEFT JOIN project_content_menu AS pcm ON pcm.type_id = pc.p_c_id
LEFT JOIN project_menu_master AS pmm ON pmm.id = pc.m_id
Im not an expert in SQL but you could try using UNION operator. like this:
select names
from table1
where lastname like k%
UNION
select names
from table2
where lastname like k%
This will combine the result from table1 and table2 and display UNIQUE NAMES in the result where the lastname is starting with k. so, if there is a JOHN KRAMER and JOHN KUTCHER then only JOHN will be displayed once.
If you want duplicate entries , too, then use UNION ALL
I'm not sure, that I understood your problem well, but if you need to add all records together, you should use: UNION ALL
Like:
select name from project_content
UNION ALL
select name from project_master
UNION ALL
select name from project_master
UNION ALL
select name from project_menu_master
Just be sure, that you have the same amount of columns in each select with the same type