MySql Join According to a Column - mysql

I want to select rows both from Report and Terminal table to create such a row like this:
+----+-------------------+---------------------+---------+-------+--------+-----+---------+------+
| id | mac_adresi | zaman | fabrika | kumes | makina | kat | sol_sag | adet |
+----+-------------------+---------------------+---------+-------+--------+-----+---------+------+
| 3 | 97-F9-2C-55-19-72 | 2017-11-18 22:43:29 | Çorum2 | Ana2 | 22 | 12 | So2 | 213 |
+----+-------------------+---------------------+---------+-------+--------+-----+---------+------+
Report table;
+----+-------------------+------+---------------------+
| id | mac_adresi | adet | zaman |
+----+-------------------+------+---------------------+
| 3 | 97-F9-2C-55-19-72 | 213 | 2017-11-18 22:43:29 |
+----+-------------------+------+---------------------+
Terminal table;
+----+-------------------+---------+-------+--------+-----+---------+
| id | mac_adresi | fabrika | kumes | makina | kat | sol_sag |
+----+-------------------+---------+-------+--------+-----+---------+
| 86 | 97-F9-2C-55-19-72 | Çorum2 | Ana2 | 22 | 12 | So2 |
+----+-------------------+---------+-------+--------+-----+---------+
In Terminal table, mac_adresi is a Primary Key,
In Report table, mac_adresi is a Foreign Key.
I have tried this query but result is not what I want to achieve.
SELECT report.*,terminal.fabrika,terminal.kumes,terminal.makina,terminal.kat,terminal.sol_sag FROM report JOIN terminal ORDER BY id DESC limit 10
How can I do this?

you should set the ON clause for join
SELECT
report.*
,terminal.fabrika
,terminal.kumes
,terminal.makina
,terminal.kat
,terminal.sol_sag
FROM report JOIN terminal on report.mac_adresi = Terminal.mac_adresi
ORDER BY id DESC limit 10

Related

make sum of one column and join it with another table

I have two tables and I want one query that gets sum of table 2 (addonAmount) column and combine it with table 1
table 1: subscriptions
+-------+--------+-------------+
| subId | userId | subDuration |
+-------+--------+-------------+
| 80 | 4607 | 6 |
| 81 | 4607 | 12 |
| 82 | 4608 | 18 |
+-------+--------+-------------+
table 2: subscriptionAddons
+---------+-------+-------------+
| addonId | subId | addonAmount |
+---------+-------+-------------+
| 15 | 80 | 4 |
| 16 | 80 | 2 |
+---------+-------+-------------+
Query I used:
SELECT subscriptions.*, subscriptionAddons.addonAmount
FROM subscriptions LEFT JOIN subscriptionAddons
ON subscriptions.subId = subscriptionAddons.subId;
what I want
+-------+--------+-------------+------------+
| subId | userId | subDuration |addonAmount |
+-------+--------+-------------+------------+
| 80 | 4607 | 6 |6 |
| 81 | 4607 | 12 |NULL |
| 82 | 4608 | 18 |NULL |
+-------+--------+-------------+------------+
You need to group by the columns that define a record and sum the column you want as result.
SELECT s.subId, s.userId, s.subDuration, sum(sa.addonAmount) as addonAmount
FROM subscriptions s LEFT JOIN subscriptionAddons sa
ON s.subId = sa.subId
GROUP BY s.subId, s.userId, s.subDuration;

How to bring columns to a table from another table by the Id?

I have this tables People, Ticket, and Report.
+----------+-------+-----+
| idPeople | Name | Age |
+----------+-------+-----+
| 1 | Name1 | 21 |
| 2 | Name2 | 37 |
| 3 | Name3 | 28 |
+----------+-------+-----+
I would like to replace the ForeingKey idPeople with columns Name and Age from People table.
+----------+------------+------------+----------+
| idTicket | ticketCol2 | ticketCol3 | idPeople |
+----------+------------+------------+----------+
| 5 | True | 01/06/99 | 1 |
| 6 | False | 01/06/99 | 2 |
| 7 | True | 01/06/99 | 4 |
+----------+------------+------------+----------+
In the Report table replace the Foreing Key idTicket with ticketCol2, Name, Age from the previous table Ticket with replaced columns (idPeople by Name, Age).
+----------+----------+------------+------------+
| idReport | idTicket | ReportCol3 | ReportCol4 |
+----------+----------+------------+------------+
| 1 | 5 | 01/06/99 | blabla |
| 2 | 7 | 01/06/99 | asdfdd |
| 2 | 6 | 01/06/99 | fooboo |
+----------+----------+------------+------------+
And I the result should be like this table and must be done in one query.
+----------+------------+------------+------------+------------+------+-----+
| idReport | ticketCol2 | ticketCol3 | ReportCol3 | ReportCol4 | Name | Age |
+----------+------------+------------+------------+------------+------+-----+
| 1 | 01/06/99 | abcd | blabla | 123456 | Name | 20 |
| 2 | 01/06/99 | bcda | asdfdd | 321456 | Name | 23 |
| 3 | 01/06/99 | asdf | fooboo | 123456 | Name | 28 |
+----------+------------+------------+------------+------------+------+-----+
I Have tried replacing the foreingkeys with LEFT JOIN and bringing some columns Name and Age to the Ticket table but now the last part where I should replace idTicket with Columns from Ticket is not working.
I have read about the nested JOINs but I cannot understand it very well, I would really appreciate some idea of how I can do it or what should I investigate. Are nested Joins the right way?
The query that I've tried to accomplish the Table Ticket.
SELECT Ticket.ticketCol2, Ticket.ticketCol3, p.Name 'Name', p.Age 'Age'
from Ticket
left join people p on (Ticket.idPeople=p.idPeople);
Try something like this:
SELECT Report.idReport,
Ticket.ticketCol2,
Ticket.ticketCol3,
Report.ReportCol3,
Report.ReportCol4,
People.Name,
People.Age
FROM People
LEFT JOIN Ticket ON Ticket.idPeople = People.idPeople
LEFT JOIN Report ON Report.idTicket = Ticket.idTicket
Like #RiggsFolly said, the Ticket.idPeople won´t match to the People.idPeople, so this will not match any rows.

How to do a ORDER BY inside a INNER JOIN to get last status update?

I need to get records of 2 tables using filters and sorting.
Tables: ra_pedidos, ra_pedido_has_pedido_status
It worked perfectly in MySQL5.0, but now in 5.5 it does not bring the correct result anymore.
I need in the same line to bring the date of the first status and last change of status of each request and ignore the canceled ones.
Example search (ra_pedido_has_pedido_status):
SELECT id_pedido, id_pedido_status, data
FROM ra_pedido_has_pedido_status
WHERE id_pedido IN (86291, 86745, 86622);
Result:
+-----------+------------------+---------------------+
| id_pedido | id_pedido_status | data |
+-----------+------------------+---------------------+
| 86291 | 1 | 2017-10-30 11:16:12 |
| 86291 | 2 | 2017-10-30 14:14:53 |
| 86291 | 3 | 2017-10-31 08:18:47 |
| 86291 | 11 | 2017-11-07 12:08:04 |
| 86622 | 1 | 2017-11-04 12:23:21 |
| 86622 | 2 | 2017-11-04 12:47:33 |
| 86622 | 3 | 2017-11-06 08:24:20 |
| 86622 | 90 | 2017-11-07 08:40:55 |
| 86745 | 1 | 2017-11-07 10:59:51 |
| 86745 | 2 | 2017-11-07 11:09:46 |
+-----------+------------------+---------------------+
Now report SQL:
[EDIT] Explain: JOIN get first match row, then the ORDER BY on SELECT inside this join force to get last row. Note that id_pedido 86622 should not list because it is canceled (last id_pedido_status = 90), and this is filtered in HAVING
SELECT o.id_pedido AS id, pus.id_pedido_status, pus.data
FROM ra_pedido AS o
INNER JOIN
(
SELECT ra_pedido_has_pedido_status.*
FROM ra_pedido_has_pedido_status
ORDER BY data DESC
) AS pus ON o.id_pedido = pus.id_pedido
WHERE o.id_pedido IN (86291, 86745, 86622)
GROUP BY o.id_pedido
HAVING id_pedido_status < 90
ORDER BY data DESC;
This is the result using MySQL 5.0, the expected:
+-------+------------------+---------------------+
| id | id_pedido_status | data |
+-------+------------------+---------------------+
| 86291 | 11 | 2017-11-07 12:08:04 |
| 86745 | 2 | 2017-11-07 11:09:46 |
+-------+------------------+---------------------+
And this is the result using MySQL 5.5, not expected:
+-------+------------------+---------------------+
| id | id_pedido_status | data |
+-------+------------------+---------------------+
| 86745 | 1 | 2017-11-07 10:59:51 |
| 86622 | 1 | 2017-11-04 12:23:21 |
| 86291 | 1 | 2017-10-30 11:16:12 |
+-------+------------------+---------------------+
What do I need to change in SQL?
Thanks and sorry my english...

Update column value by querying concatenated column values with another table value

I have two tables as below. The Id column value in both the tables mentioned below is auto-incremented.
Group
+----+-----------+----------------+
| Id | GroupId | GroupName |
+----+-----------+----------------+
| 1 | 10 | Grp1#abc.com |
| 2 | 20 | Grp2#abc.com |
| 3 | 30 | Grp3#xyz.com |
| 4 | 40 | Grp4#def.com |
+----+-----------+----------------+
Customer
+---+-----------------+------------+----------+---------------+
| Id | GroupAliasName | Domain | GroupId | CustomerName |
+---+-----------------+------------+----------+---------------+
| 1 | Grp1 | abc.com | null | Cust1 |
| 2 | Grp2 | abc.com | null | Cust2 |
| 3 | Grp3 | xyz.com | null | Cust3 |
| 4 | Grp4 | def.com | null | Cust4 |
+---+-----------------+------------+----------+---------------+
Now from Customer table 'GroupAliasName' and 'Domain' when concatenated as 'GroupAliasName#Domain' is equivalent to 'GroupName' in Group table.
Using the concatenated value from Customer table, I need to pull the 'GroupId' from the Group table and populate the same in Customer table's 'GroupId' as below
Customer
+----+----------------+------------+----------+---------------+
| Id | GroupAliasName | Domain | GroupId | CustomerName |
+----+----------------+-----------+---------+-----------------+
| 1 | Grp1 | abc.com | 10 | Cust1 |
| 2 | Grp2 | abc.com | 20 | Cust2 |
| 3 | Grp3 | xyz.com | 30 | Cust3 |
| 4 | Grp4 | def.com | 40 | Cust4 |
+----+----------------+------------+----------+---------------+
The query which I tried is as below
UPDATE Customer SET GroupId =
(SELECT GroupId FROM Group G
WHERE GroupName =
(SELECT CONCAT(GroupAliasName, '#', Domain) AS GroupName
FROM Customer
WHERE Domain IS NOT NULL) AND G.GroupName = GroupName);
But I get error as 'Subquery returns more than 1 row'.
Please suggest or provide your inputs.
Try this:
update customer as cust
inner join `group` grp on concat(cust.groupaliasname, '#', cust.domain) = grp.groupname
set cust.groupId = grp.groupId;
Try with somethings like this
UPDATE Customer as c
INNER JOIN Group as g on ( CONCAT(c.GroupAliasName, '#', c.Domain) = g.GroupName)
SET c.GroupId = g.GroupId;

MySQL JOIN 3 tables using multiple columns/keys

Complete newbie to mySQL. So any help will be appreciated.
I have 3 tables -- carts, users, actions.
carts:
+------------+-------------+-------+
| cartId | session_id | userId|
+------------+-------------+-------+
users:
+----------+-------------+
| usedId | email |
+----------+-------------+
actions:
+-------------+------------------+---- ---------+
| session_id | impressionAction | impressionId |
+-------------+------------------+-----+--------+
In carts, there is one session_id per line.
In users, there is one userId per line.
In actions, there are multiple lines per session_id counting for all the actions for that session.
I would like to JOINthe three tables getting the output to be something like
+------+-------------+--------+------------------+--------------+-------+
userId | session_id | cartId | impressionAction | impressionId | email |
+------+-------------+--------+------------------+--------------+-------+
Where there will be multiple lines per userId and session_id; essentially a flattened file. I think if we JOIN carts and users on userId resulting in say A and then JOIN A and actions' onsession_id`, we are home.
A sample expected output is:
+------------+-------------+--------+------------------+--------------+---------+
userId | session_id | cartId | impressionAction | impressionId | email |
+------------+-------------+--------+------------------+--------------+---------+
| 1234 | abc3f45 | 0001 | LOGIN | 2032 |ab#yc.com|
| 1234 | abc3f45 | 0001 | ADD | 4372 |ab#yc.com|
| 1234 | abc3f45 | 0001 | ADD | 4372 |ab#yc.com|
| 1234 | abc3f45 | 0001 | SENDMAIL | ab#yc.com |ab#yw.com|
| 4567 | def4rg4 | 0002 | LOGIN | 2032 |db#yw.com|
| 4567 | def4rg4 | 0002 | ADD | 4372 |db#yw.com|
| 4567 | def4rg4 | 0002 | REMOVE | 3210 |db#yw.com|
+------------+-------------+--------+------------------+--------------+---------+**
I don't know how to JOIN 3 tables without one common key. I don't even know what type of join it is called.
Essentially, we are trying to join 3 tables with non-overlapping keys, gathering one common key through the first JOIN and then joining the intermediate with the third one. Is this called a CROSS JOIN? If no, is there a name?
Taken from your comment above
A USER may select many products, add them to their CART; a single
USER may have multiple CARTS and at the end of the event, they can
EMAIL the cart to themselves; the ACTIONS of the user are stored in
the actions table
This is how I see the structure (having in mind your data)
+---------------------+ +---------------------+ +---------------------+
| users | | carts | | actions |
+---------------------+ +---------------------+ +---------------------+
| user_id [PK] |--| | cart_id [PK] | | impression_id [PK] |
| email | |--| user_id [FK] | | action_name |
| | | product_id [FK] | |--| session_id [FK]* |
+---------------------+ | session_id [FK]* |--| | |
| | +---------------------+
+---------------------+
As you can see above, I'm joining first with carts and them with actions because only the table carts has both, user and session data.
The [FK]* next to the session_id on carts and actions could seem as a foreign key but in this case it's not - 'cause there's no separate table for sessions where it would be placed as an PK (primary key)
You asked about join - it is the same as inner join. INNER JOIN creates a new result table by combining column values of two tables (A and B) based upon the join-predicate. The query compares each row of A with each row of B to find all pairs of rows which satisfy the join-predicate.
This is a possible content of the tables
+------------------------+
| users |
+------------------------+
| id | email |
+------+-----------------+
| 1 | first#mail.org |
| 2 | second#mail.org |
| 3 | third#mail.org |
+------+-----------------+
+------------------------------------------+
| carts |
+------------------------------------------+
| id | user_id | product_id | session_id |
+------+---------+------------+------------+
| 1 | 1 | 5 | 1aaaa |
| 2 | 2 | 5 | 2ffff |
| 3 | 3 | 8 | 3ddddd |
| 4 | 1 | 5 | 1aaaaa |
| 5 | 3 | 9 | 3bbbbb |
| 6 | 1 | 6 | 1ccccc |
+------+---------+------------+------------+
+-------------------------------+
| actions |
+-------------------------------+
| id | name | session_id |
+------+-----------+------------+
| 1 | ADD | 1aaaa |
| 2 | ADD | 2ffff |
| 3 | SENDMAIL | 3ddddd |
| 4 | ADD | 3ddddd |
| 5 | SENDMAIL | 2ffff |
| 6 | ADD | 1aaaaa |
| 7 | REMOVE | 3ddddd |
| 8 | ADD | 1ccccc |
| 9 | ADD | 3bbbbb |
| 10 | SENDMAIL | 3bbbbb |
+------+-----------+------------+
As you can see, there are six products in the table carts and exactly six add actions in the table actions. Furthermore, as you can see user with an id=1 bought three products but not at the same time, since there are two sessions; user with an id=3 as well, bought these two products in different times etc...
The SQL statement
SELECT u.user_id, c.session_id, c.cart_id, a.impression_id, a.action_name, u.email
FROM users AS u
INNER JOIN carts AS c ON c.user_id = u.user_id
INNER JOIN actions AS a ON a.session_id = c.session_id
ORDER BY u.user_id, c.session_id, c.cart_id
Results:
+---------+------------+---------+---------------+-------------+-----------------+
| user_id | session_id | cart_id | impression_id | action_name | email |
+---------+------------+---------+---------------+-------------+-----------------+
| 1 | 1aaaa | 1 | 1 | ADD | first#mail.org |
| 1 | 1aaaa | 1 | 6 | ADD | first#mail.org |
| 1 | 1aaaa | 4 | 1 | ADD | first#mail.org |
| 1 | 1aaaa | 4 | 6 | ADD | first#mail.org |
| 1 | 1cccc | 6 | 8 | ADD | first#mail.org |
| 2 | 2ffff | 2 | 5 | SENDMAIL | second#mail.org |
| 2 | 2ffff | 2 | 2 | ADD | second#mail.org |
| 3 | 3bbbb | 5 | 9 | ADD | third#mail.org |
| 3 | 3bbbb | 5 | 10 | SENDMAIL | third#mail.org |
| 3 | 3dddd | 3 | 3 | SENDMAIL | third#mail.org |
| 3 | 3dddd | 3 | 4 | ADD | third#mail.org |
| 3 | 3dddd | 3 | 7 | REMOVE | third#mail.org |
+---------+------------+---------+---------------+-------------+-----------------+
Note: There's no guarantee for session uniqueness.
(Updated) Working SQL Fiddle
UPDATE: (Finding and deleting duplicates)
I've updated the SQL Fiddle in order to simulate duplicate records (when user added the same product within the same session). With the following statement you'll be able to retrieve those duplicated rows.
SELECT c.card_id, c.user_id, c.product_id, c.session_id, a.action_name, a.impression_id
FROM cards As c
INNER JOIN actions AS a ON a.session_id = c.session_id
GROUP BY c.user_id, c.product_id, c.session_id, a.action_name
HAVING count(*) > 1
Results:
+---------+------------+------------+------------+-------------+-----------------+
| card_id | user_id | product_id | session_id | action_name | impression_id |
+---------+------------+------------+------------+-------------+-----------------+
| 1 | 1 | 5 | 1aaaa | ADD | 1 |
| 6 | 1 | 6 | 1cccc | ADD | 8 |
+---------+------------+------------+------------+-------------+-----------------+
In the SELECT part of the statement above you may omit everything except card_id and impression_id. Deleting these two duplicates in one statement is a bit tricky since you can't modify the same table selected in a sub-query within the same query. I would avoid the tricky part in this case (which involves another inner sub-query) and would delete duplicates using separate statements as following
-- delete duplicates from cards
--
DELETE FROM WHERE card_id IN (1,6)
-- delete duplicates from actions
--
DELETE FROM WHERE card_id IN (1,8)
Even better, you could check if the user already has been added a selected product and don't add it twice.
Excuse my MySql syntax, as I don't know it :-p But this is the idea
SELECT u.userId, a.session_id, c.cartId, a.impressionAction, a.impressionId, u.email
FROM Carts c
JOIN Users u on u.userId = c.UserId
JOIN Actions a on a.session_id = c.session_id
This will just merge everything together, and you'll have duplicate cart records if you have many to 1 relationships