how to search multiple tables according to criteria - mysql

I want you to give me a hand. My idea is to be able to search according to criteria. these criteria are related tables.
where I have a projects table and this has a relationship with the populations and departments table.
enter image description here
table projects
id | name | year |
4 | proyect 1 | 2019 |
6 | proyect 2 | 2020 |
table populations_project
id | project_id | name |
1 | 4 | rural |
2 | 6 | city |
table departments_project
id | project_id | name |
1 | 4 | florida |
2 | 6 | california |
the result
p_p = populations_project
d_p = departments_project
result projects
id | name | year | p_p | p_p | d_p_id | d_name
4 | proyect 1 | 2019 | City | 1 | 1 | florida
search
find 2019 and florida and city
and my inicial sql is
SELECT * FROM `projects` WHERE year BETWEEN '2019' and '2020'
with this filter the year and the table projects
see the image please

Try this one:
SELECT p.id, p.name, p.year, pp.name, pp.id, dp.id, dp.name
FROM projects p
join departments_projects dp on p.id = dp.project_id
join population_projects pp on p.id = pp.project_id
WHERE
dp.name='florida' AND
pp.name='city' AND
p.year = 2019;
Let us know if it returns your expected result

Maybe you need join table?
select *
from projects p
join populations_project pp on p.id = pp.project_id
join departments_project dp on p.id = dp.project_id
where dp.name = 'florida'
and pp.name = 'city'
and p.year BETWEEN '2019' and '2020'
SqlFiddle
In you data for proyect 1 and populations_project.name = 'city' and departments_project.name = 'florida' doesn't exists relation

Related

Join Table B to Table A only if entry in Table B equals entry in Table C

I have 3 tables. clients, sales and potential_sales.
The basic structure is as follows:
Clients Table:
+-----------+-------+----------------+
| client_id | name | address |
+-----------+-------+----------------+
| 1 | john | 12 blue ave |
| 2 | paul | 34 green lane |
| 3 | peter | 69 yellow road |
+-----------+-------+----------------+
Potential Sales Table:
+----------+------------+---------------------+
|product_id | client_id | received_free_promo |
+-----------+------------+---------------------+
| 3 | 1 | 1 |
| 4 | 2 | 0 |
| 5 | 2 | 1 |
+-----------+------------+---------------------+
Sales:
+----------+-----------+-----------+
| sales_id | client_id | product_id |
+----------+-----------+------------+
| 1 | 2 | 4 |
| 2 | 43 | 4 |
| 3 | 2 | 5 |
| 4 | 18 | 93 |
+----------+-----------+------------+
I want to join clients and potential_sales tables ONLY IF
1) received_promo equals 1 AND
2) they actually bought the promo package (i.e. the product_id for the potential sale has an entry into the sales table ). If they didn't eventually buy the free_promo product then I do not want to join the clients and potential_sales table at all. This is important - I can't simply JOIN to figure it out because this is only a small part of a bigger query and I can't afford to JOIN for no reason.
(Here is how I would like it to work. It's mainly pseudo-code to describe what I want to happen)
SELECT
c.*
FROM
clients c
LEFT JOIN potential_sales ps ON ps.client_id=c.id
LEFT JOIN sales ps ON s.product_id=ps.product_id
IF(s.sales_id) JOIN potential_sales ps ON ps.client_id=c.id
How do I do this in MySQL? I haven't come close to a solution. Please help!
Try this:
SELECT A.*, B.product_id, B.received_free_promo
FROM Clients A JOIN
(SELECT * FROM PotentialSales
WHERE received_free_promo=1) B
ON A.client_id=B.client_id
WHERE EXISTS (SELECT 1 FROM Sales C
WHERE A.client_id=C.client_id
AND B.product_id=C.product_id);
See Demo on SQL Fiddle.
What you are missing is the EXISTS clause:
SELECT
C.*,
P.*
FROM
Clients AS C
INNER JOIN PotentialSales AS P ON C.client_id = P.client_id
WHERE
P.received_free_promo = 1 AND
EXISTS (
SELECT
'the client already sold that product'
FROM
Sales AS S
WHERE
S.client_id = C.client_id AND
S.product_id = P.product_id)
Try this..." select * from client as c natural join potential as p join sales as s on p.product_id = s.product_id where received_promo = 1". select * will mention everything from all the 3 tables. You can choose what you want as the result.

MySQL multiple joins with Many-To-Many relations

I have three tables that matter to me: customer, client_assignment and customer_products. The last two are assignment tables for Many-To-Many-relations.
In client_assignment a customer of the type client gets associated with another customer (where customer_id is the parent and client_id the child).
In customer_product I associate customers with products.
A client can not be associated with a product, he inherits it from his parent-customer. In the example below this means, that Foo-1 also has product 3, because his father (Foo) has it.
customer (Customers):
+-------------+-------+----------+
| customer_id | name | type |
+-------------+-------+----------+
| 1 | Foo | customer |
| 2 | Foo-1 | client |
| 3 | Foo-2 | client |
| 4 | Bar | customer |
| 5 | Foob | customer |
+-------------+-------+----------+
client_assignment (Customer/Client-Assignment):
+-------------+-----------+
| customer_id | client_id |
+-------------+-----------+
| 1 | 2 |
| 1 | 3 |
+-------------+-----------+
customer_product (Customer/Product-Assignment):
+-------------+------------+
| customer_id | product_id |
+-------------+------------+
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |
| 4 | 3 |
| 5 | 7 |
+-------------+------------+
I want to accomplish the following: Select all customers and their respective clients that are associated with product X.
My desired result for product 3 is something like this:
+-------------+-------+--------+
| customer_id | name | parent |
+-------------+-------+--------+
| 1 | Foo | null |
| 2 | Foo-1 | 1 |
| 3 | Foo-2 | 1 |
| 4 | Bar | null |
+-------------+-------+--------+
I've been thinking about this for a bit and it seems fairly complicated. I've tried joining them like the following:
SELECT c2.customer_id, c2.name, c1.customer_id as parent
FROM customer_product p, customer c1, customer c2, client_assignment a
WHERE
c1.customer_id = p.customer_id
AND c2.customer_id = a.client_id
AND a.customer_id = c1.customer_id
AND p.product_id = 3
I know, that this query will not give me the exactly desired result, but I've created it to start with. The main problem about it is, that it does only select the clients, and not the customers themselves. Therefore I only get Foo-1 and Foo-2 as a result, but not Bar or Foo.
The question is: Is this reasonably easily achievable, and how?
You can write another SELECT that gets the customers themselves, and combine the two with UNION:
SELECT c.customer_id, c.name, NULL AS parent
FROM customer AS c
JOIN customer_product AS p ON c.customer_id = p.customer_id
WHERE c.type = 'customer'
AND p.product_id = 3
UNION
SELECT c2.customer_id, c2.name, c1.customer_id AS parent
FROM customer_product AS p
JOIN customer AS c1 ON c1.customer_id = p.customer_id
JOIN client_assignment AS a ON a.customer_id = c1.customer_id
JOIN customer AS c2 ON c2.customer_id = a.client_id
WHERE c2.type = 'client'
AND p.product_id = 3
Because you have to get names of both clients and parents of the client, a way of doing it is by using UNION.
with customer_names as (select customer_id from s_customer_product where product_id =3),
client_names as (select client_id , customer_id as Parent_id from s_client_assignment join customer_names using(customer_id))
select customer_id , name , null as Parent from s_customers join customer_names using(customer_id)
union
select a.client_id , b.name , a.parent_id as Parent from client_names a, s_customers b where b.customer_id = a.client_id;

Limit this JOIN query so one result for each left-side table is returned?

I have these two tables:
Person:
+----+-------+
| ID | name |
+----+-------+
| 1 | John |
| 2 | Frank |
+----+-------+
Position:
+----+---------+----------+------------+
| ID | name | personID | startDate |
+----+---------+----------+------------+
| 1 | Cashier | 1 | 2013-01-01 |
| 2 | Manager | 1 | 2013-04-23 |
| 3 | Cashier | 2 | 2014-02-01 |
+----+---------+----------+------------+
The Position table tracks various positions that a person has held.
How can I create a listing that shows each person and their current position (which would be whatever position has the latest start date)? Essentially I need to limit the JOIN of the Position table to only return one result.
I tried the following code.
SELECT p.id, h.positionID FROM person p JOIN position h ON p.id = h.personID
Try the following :-
select p.ID, pp.name PersonName, p.name PositionName ,p.startDate
from Position p
inner join
(select personID, max(startDate) sdate from Position group by personID) as a
on p.personID = a.personID and p.startDate = a.sdate
left join Person pp
on pp.ID = p.personID
Yet, it is highly advised that you post the code that you tried.
SQL Fiddle

MYSQL JOIN two tables limit results from second table by date

I am trying to retrieve date from two tables using a MYSQL query. I want to join them together were categories.cat_id=topics.topic_cat. Multiple entries may have the same topic_cat, so I only want to SELECT the most recent, which is equal to MAX(topic_date).
The following query shows the correct information from topics, with only one result per topic_cat and that result having the most recent date.
SELECT topic_subject, topic_cat, topic_date
FROM topics
GROUP BY topic_cat DESC
Multiple rows may have the same value for topic_cat, but I only want to retrieve and join only the most recent, MAX(topic_date) and then join to a query which shows the following information from the categories table.
SELECT categories.cat_id, categories.cat_name, categories.cat_description, topics.topic_subject, topics.topic_cat, topics.topic_date, topics.topic_by
FROM categories
LEFT JOIN topics
ON categories.cat_id=topics.topic_cat
GROUP BY cat_id;
This query displays the correct information, except one thing. It shows the topic_cat with the oldest entry, or MIN(topic_date). I have tried the following to get the topic_cat by newest entry or MAX(topic_date), but without success.
SELECT categories.cat_id, categories.cat_name, categories.cat_description
FROM categories
LEFT JOIN (SELECT topic_subject, topic_cat, topic_date, topic_by
FROM topics
GROUP BY topic_cat DESC) AS topics
ON categories.cat_id=topics.topic_cat
Any help or suggestions would be greatly appreciated.
Ok, so here is the sample data and associated desired result.
Table 1 = categories
_______________________________________________________
| cat_id | cat_name | cat_description |
-------------------------------------------------------
| 1 | james | Some information about james|
-------------------------------------------------------
| 2 | myo | Some information about myo |
-------------------------------------------------------
| 3 | brandon | Some information about brandon |
-------------------------------------------------------
Table 2 = topics
__________________________________________________
| topic_subject | topic_cat | topic_date | topic_by |
----------------------------------------------------------
| marcos | 2 | 2013-9-28 | User 1 |
---------------------------------------------------------
| ferdinand | 2 | 2013-9-29 | User 2 |
---------------------------------------------------------
| maria luisa | 2 | 2013-9-30 | User 1 |
---------------------------------------------------------
| Isabella | 1 | 2013-8-24 | User 3 |
--------------------------------------------------------
| Carlos | 3 | 2012-6-21 | User 2 |
--------------------------------------------------------
| Enrique | 3 | 2011-4-2 | User 3 |
---------------------------------------------------------
I would like the query to return the following data based on the above tables:
_________________________________________________________________________________________________
| cat_id | cat_name | cat_description | topic_subject | topic_cat | topic_date | topic_by |
----------------------------------------------------------------------------------------------------------------
| 1 | james | Some information about james | Isabella | 1 | 2013-8-24 | User 3 |
----------------------------------------------------------------------------------------------------------------
| 2 | myo | Some information about myo | maria luisa | 2 | 2013-9-30 | User 1 |
----------------------------------------------------------------------------------------------------------------
| 3 | brandon | Some information about brandon | Carlos | 3 | 2012-6-21 | User 2 |
----------------------------------------------------------------------------------------------------------------
I hope that clarifies things.
Try This:
###
SELECT * FROM categories c
LEFT JOIN topics t ON c.cat_id = t.topic_cat
WHERE c.cat_id IN (SELECT t1.cat_id FROM (
SELECT c.cat_id, c.cat_name, MAX(t.topic_date) AS maxdate FROM categories c
LEFT JOIN topics t ON c.cat_id = t.topic_cat
GROUP BY c.cat_name
) as t1 WHERE t1.maxdate = t.topic_date OR t.topic_date IS NULL );
### without nulls
SELECT * FROM categories c
LEFT JOIN topics t ON c.cat_id = t.topic_cat
WHERE c.cat_id IN (SELECT t1.cat_id FROM (
SELECT c.cat_id, c.cat_name, MAX(t.topic_date) AS maxdate FROM categories c
LEFT JOIN topics t ON c.cat_id = t.topic_cat
GROUP BY c.cat_name
) as t1 WHERE t1.maxdate = t.topic_date);
Try changing
LEFT JOIN (SELECT topic_subject, topic_cat, topic_date, topic_by
FROM topics
GROUP BY topic_cat DESC) AS topics
to:
LEFT JOIN (SELECT topic_subject, topic_cat, topic_date, topic_by
FROM topics
GROUP BY topic_cat
ORDER BY topic_date DESC
LIMIT 0,1) AS topics

JOIN 4 Tables with meta_table

I have this database structure:
sites
id | name
1 | Site 1
2 | Site 2
locations
id | city
23 | Baltimore
24 | Annapolis
people
id | name
45 | John
46 | Sue
sites_meta
id | site_id | meta_name | meta_value
1 | 1 | local | 23
2 | 1 | person | 45
3 | 2 | local | 24
4 | 2 | person | 46
So, as you can see, Site 1 (id 1) is in Baltimore and is associated with John, Site 2 (id 2) is in Annapolis and associated with Sue.
I need to figure out a clever sql statement that can return
id | name | id | city | id | name
1 | Site 1 | 23 | Baltimore | 45 | John
2 | Site 2 | 24 | Annapolis | 46 | Sue
I would be super appreciative if anyone can help me out. I've tried a few combinations of a select statement, but I keep getting stuck with using two values from the sites_meta table.
select
s.id as siteId,
s.name as siteName,
max(l.id) as locationId,
max(l.city) as city,
max(p.id) as personId,
max(p.name) as personName
from
sites_meta sm
join sites s on s.id = sm.site_id
left join locations l on l.id = sm.meta_value and sm.meta_name = 'local'
left join people p on p.id = sm.meta_value and sm.meta_name = 'person'
group by
s.id,
s.name
You can probably imagine how this kind of "meta" table might become a pain... especially as more items are added to it.
Instead, you might consider replacing it with two new tables, sites_locations and sites_people.
SELECT
s.id,s.name,l.id,l.city,p.id,p.name
FROM
sites s
INNER JOIN sites_meta sm1 ON s.id = sm1.site_id
INNER JOIN sites_meta sm2 ON s.id = sm2.site_id
INNER JOIN locations l ON sm1.meta_value = l.id AND sm1.meta_name = 'local'
INNER JOIN people p ON sm2.meta_value = p.id AND sm2.meta_name = 'person'
;