mysql where multiple fields in - mysql

I want to extract unique minlat, minlng based on city and country then want to find all id which have this pair I mean something like
select id from spots
where (minlat,minlng) in
(select s.minlat, s.minlng from spots s, spot_cards sc
where sc.spot_id=s.id and sc.country="italy"
and
(sc.city="perugia" or sc.locality="perugia" or sc.sublocality="perugia")
);
Structure of spots table is:
+----+-----------+-----------+
| id | minlat | minlng |
+----+-----------+-----------+
I created spot_cards table structure as
+---------+-------------+-------------+---------+--------+
| spot_id | sublocality | locality | country | city |
+---------+-------------+-------------+---------+--------+
by executing below query
insert into spot_cards(spot_id)
select id from spots
group by minlat,minlng
order by id
Any help is appreciated.

I think you need something like this:
Join the spots table to get all the records you want, then join again on the spots table to get the coordinates. Do a DISTINCT to get rid of any possible duplicates.
SELECT DISTINCT s2.id from spots s
INNER JOIN spot_cards sc
ON sc.spot_id=s.id
INNER JOIN spots s2
ON s.minlat = s2.minlat AND s.minlng = s2.minlng
WHERE sc.country="italy"
AND (sc.city="perugia" or sc.locality="perugia" or sc.sublocality="perugia")

Related

Slow SELECT with LEFT JOIN over 4 tables

My database has 4 tables: org_addresses, org_main, zipcodes and cities.
The table org_addresses contains address data for organizations, the table org_main contains the main data for these organizations, the table zipcodes contains city zipcodes, and the table cities contains city names.
org_addresses:
| id | org_id | address_line | zipcode |
org_main:
| id | name |
zipcodes
| id | city_id | zipcode |
cities
| id | name |
In my query, I join all 4 tables using LEFT JOIN together to output complete data as a list with 1600 organizations.
As soon as I join the table zipcodes via LEFT JOIN and then join to the table cities, the request slows down to 4 seconds. Without the table zipcodes, the query takes 0.009 seconds.
SELECT a.org_id
, a.address_line2
, a.zipcode
, m.name
FROM org_addresses a
LEFT
JOIN org_main m
ON a.org_id = m.id
LEFT
JOIN zipcodes z
ON a.zipcode = z.zipcode
LEFT
JOIN cities c
ON z.city_id = c.id
What am I doing wrong?
You should look at the execution plans of the queries to see what is happening.
My guess would be that zipcodes(zipcode) is not indexed (and probably not cities(city). It is curious that you are not joining on the tables id instead.
be sure you have proper index
on table org_addresses composite index on columns (org_id, zipcode)
on table zipcodes column composite index on columns ( city_id, zipcode)
on table cities on column (id)

MySQL count unique over multiple tables

I have two tables:
products product_eans
+--+-----------+ +----------+-------------+
|id|name | |product_id|ean |
+--+-----------+ +----------+-------------+
| 1|hello world| | 1|4053804303361|
+--+-----------+ +----------+-------------+
| 2|hello mars | | 1|4053804304788|
+--+-----------+ +----------+-------------+
| 2|4053804304825|
+----------+-------------+
I now want to count the (unique) products that has the string 4788 in their name or in one of their EANs. The result in the example would be 1 (one product has an EAN that contains the search string 4788)
I have managed this with
SELECT
COUNT(DISTINCT products.id) AS count
FROM
products
WHERE
products.name LIKE "%4788%" OR
(SELECT
GROUP_CONCAT(ean)
FROM
product_eans
WHERE
product_id = product.id) LIKE "%4788%"`
but it’s incredible slow with thousands of rows in both tables.
What is the most efficient way for a query like this?
Using "double-ended wildcards" is never going to be fast because you won't get use of indexing so the tables will be scanned. An inner join is probably the most efficient
SELECT COUNT(DISTINCT e.products_id)
FROM product_eans e
inner join products p on e.products_id = p.id
WHERE e.ean LIKE '%4788%'
OR p.name LIKE '%4788%'
but one other possibility is to avoid the OR in tha wheer clause by using a union query like this:
SELECT
COUNT(*)
FROM (
SELECT
product_id
FROM product_eans
WHERE ean LIKE '%4788%'
UNION
SELECT
id
FROM products
WHERE name LIKE '%4788%'
) d
After being inspired by Used_By_Already, I came across a simple idea:
SELECT
COUNT(DISTINCT products.id) AS count
FROM
products
WHERE
products.name LIKE "%4788%" OR
products.id in (SELECT product_id FROM product_eans WHERE ean "%4788%")
It's super fast now. So thanks to Used_By_Already.

MySQL join and column names

Let's say that I have the following tables in my MySQL database:
TABLE Products
| id | some_column1 | some_column2 |
TABLE ProductProperties
| id | product_id | name |
Oversimplified, but sufficient. Now I want to get all products with properties. I do:
SELECT * FROM `Products` JOIN `ProductProperties` ON Products.id = ProductProperties.product_id
What do I get?
| id | some_column1 | some_column2 | id | product_id | name |
It's not cool, and I want to make it cool in one of the two ways:
1) To get the array of objects like in Product table, but extended by one more member, which would be the array of properties which matched JOIN. I've sort of figured out already that it's impossible?
2) To get the array like this (I'd still have to iterate over it in PHP to join all properties in one product into one object):
| product_id | some_column1 | some_column2 | property_id | product_id | name |
So I'd like to rename the column ProductProperties.id into ProductProperties.property_id. If I could remove ProductProperties.product_id from the output too, that would be ideal, but for now, I only want the way to rename one column in the output. Or to prefix it by table name. Or something like that.
Doable?
You should explicitly name the columns and not use *. Then, don't return redundant columns:
SELECT p.id as productid, p.some_column1, p.some_column2,
pp.id as ProductPropertiesId, pp.name
FROM `Products` p JOIN `ProductProperties` pp
ON p.id = pp.product_id
Also, table aliases make such a query more readable.
SELECT Products.id product_id,
Products.some_column1,
Products.some_column2,
ProductProperties.id property_id,
ProductProperties.name
FROM `Products`
JOIN `ProductProperties`
ON Products.id = ProductProperties.product_id

mysql - selecting groups and users all in same query

I have following two tables 'USERS' and 'GROUPS':
USERS
-id
-name
-groupid
GROUP
-id
-name
I'd like to return all users along with their group's name and group id. It should be an outer join on group id field correct?
A simple INNER JOIN should be enough:
SELECT `USERS`.*, `GROUP`.name AS group_name
FROM `USERS`, `GROUP`
WHERE `USERS`.groupid = `GROUP`.id
You're going to want to look at the JOIN statement
Doing this from my phone, so pardon any moderately incorrect syntax, but something a long the lines of
Edit: other guy's syntax is better. It's too early here
You can use a LEFT JOIN between users and groups so that users who are not in a group still show up in the result set, but with group name and id NULL:
SELECT
a.*,
b.name AS group_name
FROM
users a
LEFT JOIN
`group` b ON a.group_id = b.id
Side note: Ensure that you're encasing the table name group in backticks because it is a reserved keyword.
The result-set should look something like:
id | name | group_id | group_name
-----------------------------------------------------------------------------
1 | John | 5 | ThisIsGroup5
3 | Tim | 3 | ThisIsGroup3
6 | NotInGroup | NULL | NULL
Changing LEFT to INNER in the above query would INNER JOIN the two tables and exclude the user "NotInGroup" from the result-set.

How to count the number of instances of each foreign-key ID in a table?

Here's my simple SQL question...
I have two tables:
Books
-------------------------------------------------------
| book_id | author | genre | price | publication_date |
-------------------------------------------------------
Orders
------------------------------------
| order_id | customer_id | book_id |
------------------------------------
I'd like to create a query that returns:
--------------------------------------------------------------------------
| book_id | author | genre | price | publication_date | number_of_orders |
--------------------------------------------------------------------------
In other words, return every column for ALL rows in the Books table, along with a calculated column named 'number_of_orders' that counts the number of times each book appears in the Orders table. (If a book does not occur in the orders table, the book should be listed in the result set, but "number_of_orders" should be zero.
So far, I've come up with this:
SELECT
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date,
count(*) as number_of_orders
from books
left join orders
on (books.book_id = orders.book_id)
group by
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date
That's almost right, but not quite, because "number_of_orders" will be 1 even if a book is never listed in the Orders table. Moreover, given my lack of knowledge of SQL, I'm sure this query is very inefficient.
What's the right way to write this query? (For what it's worth, this needs to work on MySQL, so I can't use any other vendor-specific features).
Your query is almost right and it's the right way to do that (and the most efficient)
SELECT books.*, count(orders.book_id) as number_of_orders
from books
left join orders
on (books.book_id = orders.book_id)
group by
books.book_id
COUNT(*) could include NULL values in the count because it counts all the rows, while COUNT(orders.book_id) does not because it ignores NULL values in the given field.
SELECT b.book_id,
b.author,
b.genre,
b.price,
b.publication_date,
coalesce(oc.Count, 0) as number_of_orders
from books b
left join (
select book_id, count(*) as Count
from Order
group by book_id
) oc on (b.book_id = oc.book_id)
Change count(*) to count(orders.book_id)
You're counting the wrong thing. You want to count the non-null book_id's.
SELECT
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date,
count(orders.book_id) as number_of_orders
from books
left join orders
on (books.book_id = orders.book_id)
group by
books.book_id,
books.author,
books.genre,
books.price,
books.publication_date
select author.aname,count(book.author_id) as "number_of_books"
from author
left join book
on(author.author_id=book.author_id)
GROUP BY author.aname;