Joinin multiple tables with double group by,double count - mysql

I am trying to expand my Select to handle displaying number of files associated with Unique "NR_REKLAMACJI". I Got table 'rtransportowa' where i keep all details, 'klienci' where i get Name and Surname and now im trying to join table 'pliki' or 'files' as well, to keep track on how many files there are for corresponding 'NR_REKLAMACJI'.
Tried adding Count(files.FileName) on select and then Inner joining it and using group by NR_REKLAMACJI, files.NR_REK
SELECT
`NR_REKLAMACJI`,
COUNT(NR_REKLAMACJI) AS 'ilosc reklamowanego towaru',
CONCAT(klienci.IMIE, ' ', klienci.NAZWISKO) AS 'Klient',
CONCAT(users.IMIE, ' ', users.NAZWISKO) AS 'Osoba zajmująca się',
DOK_FV,
klienci.NAZWA_FIRMY,
DATA
FROM
`rtransportowa`
INNER JOIN klienci ON ID_R = klienci.ID_KLIENTA
INNER JOIN users ON ID_U = users.ID_USER
group by
NR_REKLAMACJI
My goal is to group table 'rtransportowa' to show unique 'NR_REKLAMACJI" and count number of "NR_REKLAMACJI" from rtransportowa and files,
I got TABLE1 with not unique field NAME, TABLE 2 having also field NAME, and i want to group it by showing all things from TABLE1 + Count(NAME), grouping it by field NAME, and for this add Count of (TABLE2.NAME) also grouped by the TABLE1.NAME
+------+-------------+--------------------+
| Name | Count(Name) | Count(TABLE2.Name) |
+------+-------------+--------------------+
| aaa | 2 | 3 |
| bbb | 3 | 0 |
| ccc | 1 | 45 |
+------+-------------+--------------------+

Related

MySql : how to join this two tables with multiple pivot

I want to get the last activity of my client but i dont know how to that that with two tables that have more than one pivot. Please look at to the example below :
table product
--------------------------------------------------------------------------------------------------------------------------------------
id | name | check_mo (Activity1) | check_mo_account_id | check_pa (Activity2) | check_pa_account_id
--------------------------------------------------------------------------------------------------------------------------------------------
1 | product1 | 01/02/2020 | 63 | 05/02/2020 | 100
2 | product2 | 01/03/2020 | 23 | 10/03/2020 | 63
-----------------------------------------------------------------------------------------------------------------------------------
Table account
--------------------------------
id | name
--------------------------------
23 | name1
63 | name2
100 | name3
--------------------------------
I want this result (last activity is the lastest date of (check_mo and check_pa). and relationship between tables is (account.id => product.check_mo_account_id and product.check_pa_account_id))
------------------------------------------------
id | name | last activity
-------------------------------------------------
23 | name1 | 01/03/2020
63 | name2 | 10/03/2020
100 | name3 | 05/02/2020
-------------------------------------------------
Unpivot the columns. In MySQL, you can use union all. Use join to bring in the names and then a window function to get the most recent date:
select pn.*
from (select pn.*, max(dte) over (partition by name) as max_dte
from ((select n.name, p.check_mo as dte, p.check_mo_account_id as account_id
from product p join
name n
on p.check_mo_account_id = n.id
) union all
(select n.name, p.check_pa, p.check_pa_account_id as account_id, p.check_pa
from product p join
name n
on p.check_mo_account_id = n.id
)
) pn
) pn
where dte = max_dte;
If I understand correctly, you have two check IDs and two check dates in one row, but want to treat them equally, just as if you had just one table with one check ID and one check date per row. Use UNION ALL to get this table. Then find the maximum date per ID and join this to the account table.
select id, account.name, aggregated.last_activity
from account
join
(
select id, max(check) as last_activity
from
(
select check_mo_account_id as id, check_mo as check from product
union all
select check_pa_account_id as id, check_pa as check from product
) unioned
group by id
) aggregated using (id)
order by id;

SQL left join: how to return the newest from tableB and grouped by another field

I've been trying for two days, without luck.
I have the following simplified tables in my database:
customers:
| id | name |
| 1 | andrea |
| 2 | marco |
| 3 | giovanni |
access:
| id | name_id | date |
| 1 | 1 | 5000 |
| 2 | 1 | 4000 |
| 3 | 2 | 1500 |
| 4 | 2 | 3000 |
| 5 | 2 | 1000 |
| 6 | 3 | 6000 |
| 7 | 3 | 2000 |
I want to return all the names with their last access date.
At first I tried simply with
SELECT * FROM customers LEFT JOIN access ON customers.id =
access.name_id
But I got 7 rows instead of 3 as expected. So I understood I need to use GROUP BY statemet as the following:
SELECT * FROM customers LEFT JOIN access ON customers.id =
access.name_id GROUP BY customers.id
As far I know, GROUP BY combines using a random row. In fact I got unordered access dates with several tests.
Instead I need to group every customer id with its corresponding latest access! How this can be done?
You have to get the latest date from the access table with a group by on the the name_id, then join this result with the customer table. Here is the query:
select c.id, c.name, a.last_access_date from customers c left join
(select id, name_id, max(access_date) last_access_date from access group by name_id) a
on c.id=a.name_id;
Here is a DEMO on sqlfiddle.
I think this is what you'd like to achieve:
SELECT c.id, c.name, max(a.date) last_access
FROM customers c
LEFT JOIN access a ON c.id = a.name_id
GROUP BY c.id, c.name
The LEFT join will return all entries in table customers regardless if the join criteria (c.id = a.name_id) is satisfied. This means that you might get some NULL entries.
Example:
Simply add a new row in the customers table (id: 4, name: manuela). The output will have 4 rows and the newest row will be (id: 4, last_access: null)
I would do this using a correlated subquery in the ON clause:
SELECT a.*, c.*
FROM customers c LEFT JOIN
access a
ON c.id = a.name_id AND
a.DATE = (SELECT MAX(a2.date) FROM access a2 WHERE a2.name_id = a.name_id);
If this statement is true:
I need to group every customer id with its corresponding latest access! How this can be done?
Then you can simply do:
select a.name_id, max(a2.date)
from access a
group by a.name_id;
You do not need the customers table because:
All customers are in access, so the left join is not necessary.
You need no columns from customers.

Join two tables using multiple rows in the join

I have two tables
Table: color_document
+----------+---------------------+
| color_id | document_id |
+----------+---------------------+
| 180907 | 4270851 |
| 180954 | 4270851 |
+----------+---------------------+
Table: color_group
+----------------+-----------+
| color_group_id | color_id |
+----------------+-----------+
| 3 | 180954 |
| 4 | 180907 |
| 11 | 180907 |
| 11 | 180984 |
| 12 | 180907 |
| 12 | 180954 |
+----------------+-----------+
Is it possible for a query to get a result that looks something like this using multiple color id's to join the two tables?
Result
+----------------+--------------+
| color_group_id | document_id |
+----------------+--------------+
| 12 | 4270851 |
+----------------+--------------+
Since Color Group 12 is the only group that has the exact same set of Colors that Document 4270851 has.
I've got some bad data that i'm being forced to work with so I've had to manufacture the color groups by finding each unique set of color_id's associated with document_id's. I'm trying to then create a new relationship directly between my manufactured color groups and documents.
I know I could probably do something with a GROUP_CONCAT to make a pseudo key of concatenated color ids, but I'm trying to find a solution that would also work in, say, Oracle. Am I barking up the completely wrong tree with this logic?
My ultimate goal is to be able to have a single row in a table that would represent any number of Colors that are associated with a Document to be exported to a completely different system than the one I'm working with.
Any thoughts/comments/suggestions are greatly appreciated.
Thank you in advance for looking at my question.
Do a normal join of the two tables, and count the number of rows in each pairing. Then test whether this is the same as the number of times each of the items appears in the original tables. If all are the same, then all color IDs must match.
SELECT a.color_group_id, a.document_id
FROM (
SELECT color_group_id, document_id, COUNT(*) ct
FROM color_document d
JOIN color_group g ON d.color_id = g.color_id
GROUP BY color_group_id, document_id) a
JOIN (
SELECT color_group_id, COUNT(*) ct
FROM color_group
GROUP BY color_group_id) b
ON a.color_group_id = b.color_group_id and a.ct = b.ct
JOIN (
SELECT document_id, COUNT(*) ct
FROM color_document
GROUP BY document_id) c
ON a.document_id = c.document_id and a.ct = c.ct
SQLFIDDLE
If i understand your question correct you just have to join the two tables and then group the results by color_group_id an document_id.
SQL Fiddle
select color_group_id, document_id
from
color_document cd join
color_group cg
on cd.color_id = cg.color_id
group by color_group_id, document_id
That query will give you this result set:
COLOR_GROUP_ID DOCUMENT_ID
3 4270851
4 4270851
11 4270851
12 4270851
Is that what you want?

Showing rows as columns in MySQL

I have a networks table and a groups table and they are linked by each group being connected to a network.
Each group have a type and some of these groups are special type of groups.
I'm trying to run query that will display each group that is a a special type to be displayed as a column showing how many people are in that group type.
Is that something that is possible? Having each group type being displayed as a column header.
Data:
Networks
id | name
1 | networka
2 | networkb
groups
id | name | type | network
1 | groupa | 1 | 1
2 | groupb | 2 | 2
3 | groupc | 3 | 1
type
id | name | special
1 | speciala | 0
2 | specialb | 1
I currently running:
SELECT Name FROM (
SELECT groups.Name FROM groups INNER JOIN group_types on groups.Type = group_types.Id WHERE group_types.SpecialType = 1 Group by groups.Type
) as s
which returns the list of groups with special type. But if I want to get more information such as the number of members in that group assuming I have a group_members table that links back to the groups table or the numbers of groups with that type.
I currently get two a row:
name
specialb
but I actually want to return back
specialb
(sub query to get more values for that special group)
If I'm understanding what you want correctly, write this:
select g.name, t.name, count(*)
from groups as g left join group_members as gm on gm.group=g.id left join types as t on t.id=g.type
group by g.name, t.name
then copy and paste into Excel using paste special > transpose.

MySQL conditionally populate column 3 based on DISTINCT involving 2 other columns in one table

Had a good read through similar topics but I can't quite a) find one to match my scenario, or b) understand others enough to fit / tailor / tweek to my situation.
I have a table, the important fields being;
+------+------+--------+--------+
| ID | Name | Price |Status |
+------+------+--------+--------+
| 1 | Fred | 4.50 | |
| 2 | Fred | 4.50 | |
| 3 | Fred | 5.00 | |
| 4 | John | 7.20 | |
| 5 | John | 7.20 | |
| 6 | John | 7.20 | |
| 7 | Max | 2.38 | |
| 8 | Max | 2.38 | |
| 9 | Sam | 21.00 | |
+------+------+--------+--------+
ID is an auto-incrementing value as records get added throughout the day.
NAME is a Primary Key field, which can repeat 1 to 3 times in the whole table.
Each NAME will have a PRICE value, which may or may not be the same per NAME.
There is also a STATUS field that need to be populated based on the following, which is actually the part I am stuck on.
Status = 'Y' if each DISTINCT name has only one price attached to it.
Status = 'N' if each DISTINCT name has multiple prices attached to it.
Using the table above, ID's 1, 2 and 3 should be 'N', whilst 4, 5, 6, 7, 8 and 9 should be 'Y'.
I think this may well involve some form of combination of JOINs, GROUPs, and DISTINCTs but I am at a loss on how to put that into the right order for SQL.
In order to get the count of distinct Price values per name, we must use a GROUP BY on the Name field, but since you also want to display all names ungrouped but with an additional Status field, we must first create a subselect in the FROM clause which groups by the name and determines whether the name has multiple price values or not.
When we GROUP BY Name in the subselect, COUNT(DISTINCT price) will count the number of distinct price values for each particular name. Without the DISTINCT keyword, it would simply count the number of rows where price is not null.
In conjunction with that, we use a CASE expression to insert N into the Status column if there is more than one distinct Price value for the particular name, otherwise, it will insert Y.
The subselect only returns one row per Name, so to get all names ungrouped, we join that subselect to the main table on the condition that the subselect's Name = the main table's Name:
SELECT
b.ID,
b.Name,
b.Price,
a.Status
FROM
(
SELECT Name, CASE WHEN COUNT(DISTINCT Price) > 1 THEN 'N' ELSE 'Y' END AS Status
FROM tbl
GROUP BY Name
) a
INNER JOIN
tbl b ON a.Name = b.Name
Edit: In order to facilitate an update, you can incorporate this query using JOINs in the UPDATE like so:
UPDATE
tbl a
INNER JOIN
(
SELECT Name, CASE WHEN COUNT(DISTINCT Price) > 1 THEN 'N' ELSE 'Y' END AS Status
FROM tbl
GROUP BY Name
) b ON a.Name = b.Name
SET
a.Status = b.Status
Assuming you have an unfilled Status column in your table.
If you want to update the status column, you could do:
UPDATE mytable s
SET status = (
SELECT IF(COUNT(DISTINCT price)=1, 'Y', 'N') c
FROM (
SELECT *
FROM mytable
) s1
WHERE s1.name = s.name
GROUP BY name
);
Technically, it should not be necessary to have this:
FROM (
SELECT *
FROM mytable
) s1
but there is a mysql limitation that prevents you to select from the table you're updating. By wrapping it in parenthesis, we force mysql to create a temporary table and then it suddenly is possible.