select using join with 2 tables - mysql

Somebody help with this query, i would like to select just the company and the last login date
I've tried several joins, unsuccessfully
certainly using the wrong way, without logic
COMPANY TABLE
id|company|
1 | compA |
2 | compB |
3 | compC |
.
LOGIN TABLE
id| data |FKcompanyTable
1 | 2018-05-25 11:05:46 | 1
2 | 2018-05-25 11:07:46 | 1
3 | 2018-05-25 11:06:46 | 2
4 | 2018-05-25 11:05:46 | 3
5 | 2018-05-25 11:08:46 | 3

all you have to do is to use group by company_id and select max date as last login date
select
COMPANY.id as "company_name",
max(LOGIN.data) as "last_login"
from
COMPANY
inner join LOGIN on(LOGIN.FKcompanyTable = COMPANY.id)
group by COMPANY.id
hope this could help

Select company.id,company.company,tbl_lastdate.lastdate
from company left join (select id as companyid,max(data) as lastdate from Login group by FKcompanyTable)tbl_lastdate on company.id = tbl_lastdate.companyid

For your case, rather than using JOIN, I'd go with SubQuery.
SELECT
c.company AS 'company_name',
(SELECT data FROM LOGIN WHERE FKcompanyTable = c.id ORDER BY id DESC LIMIT 1 ) as 'last_login'
FROM COMPANY c

Related

MySQL count function with a join?

I've two tables.
User(id,name)
Finance(id,item_id,amount,user_id)
My use case is
users are the employees (sales guys) of the organization.
When they sell an item finance table get updated with a new record of that sold item's serial id.
I want to get the user names along with the total value of the sales they made.
User
id | name
1 | Dinesh
2 | Pathum
3 | Naveed
Finance
id | item_id | amount | user_id
1 | 1 | 2000 | 1
2 | 2 | 2000 | 1
3 | 3 | 1000 | 3
4 | 4 | 500 | 3
Expected output
Dinesh 4000
Pathum 0
Naveed 1500
How do I achieve this using MySQL?
The query is like the following:
SELECT u.name as 'Agent Name',
if(sum(f.amount) IS NULL, 0,sum(f.amount)) as Total,
f.createdAt
FROM users u LEFT JOIN finance f
ON u.id = f.user_id
GROUP BY u.id, u.name, f.createdAt
ORDER BY f.createdAt DESC
Here is a working SQL Fiddle.
Join em, group em, sum em.
SELECT usr.name AS UserName, COALESCE(SUM(fin.amount),0) AS TotalAmount
FROM `User` usr
LEFT JOIN `Finance` fin ON fin.user_id = usr.id
GROUP BY usr.id, usr.name
ORDER BY usr.id;
Test on db<>fiddle here
Another way:
SELECT Name,SUM(IFNULL(amount,0)) AS "Total" FROM (SELECT Name,amount FROM user LEFT JOIN finance ON user.id=finance.user_id) a GROUP BY Name;

Select all rows with multiple occurrences - on same day

I have a single MySQL table with the name 'checkins' and 4 columns.
id | userIDFK | checkin_datetime | shopId
------------------------------------------------
1 | 1 | 2018-01-18 09:44:00 | 3
2 | 2 | 2018-01-18 10:32:00 | 3
3 | 3 | 2018-01-18 11:19:00 | 3
4 | 1 | 2018-01-18 17:57:00 | 3
5 | 1 | 2018-01-18 16:31:00 | 1
6 | 1 | 2018-01-19 08:31:00 | 3
Basically I want to find rows where users have checked-in more than once (>=2) on the same day and the same shop. So for instance if a user checks-in as in rows with ids 1 and 4 (same user, same day, same shop), the query should return a hit with the the entire rows (id, userIDFK, checkin_datetime, shopId). Hope this makes sense.
I already tried using
SELECT id, userIDFK, checkin_datetime, shopId
FROM (
SELECT * FROM 'checkins' WHERE COUNT(userIDFK)>=2 AND COUNT(shopId)>=2
)
The same day part I have no clew how to do it, and I know this query is way off, but this is the best I could.
You can try grouping by userId checkin_date and shopID
SELECT userIDFK, checkin_datetime, shopId,COUNT(SHOPiD)
FROM checkins
GROUP BY userIDFK, DATE(checkin_datetime), shopId
HAVING COUNT(SHOPID)>1
EDIT
You can include a subquery to get all lines:
select b.id,b.userIDFK, b.checkin_datetime, b.shopId
from checkins b
where (SELECT COUNT(SHOPiD)
FROM checkins a
where a.userIDFK=b.userIDFK and date(a.checkin_datetime)=date(b.checkin_datetime) and a.shopId=b.a.shopId
GROUP BY userIDFK, DATE(checkin_datetime), shopId)>1
GROUPBY can be used to get the multiple occurrences.
SELECT id, userIDFK, checkin_datetime, shopId
FROM checkins
GROUP BY userIDFK, DATE(checkin_datetime), shopId
HAVING count(id) > 1;
Hope it helps!
EDIT:
Using inner join you can achieve it. Here is the query:
SELECT c1.* FROM checkins c1 INNER JOIN checkins c2
ON c1.userIDFK = c2.userIDFK
AND date(c1.checkin_datetime) = date(c2.checkin_datetime)
AND c1.shopId = c2.shopId
AND c1.id != c2.id
Cheers!!

MySQL - Get records from INNER JOIN not between dates

I have two tables
Accounts:
+------------+--------+
| accountsid | name |
+------------+--------+
| 1 | Bob |
| 2 | Rachel |
| 3 | Mark |
+------------+--------+
Sales Orders
+--------------+------------+------------+--------+
| salesorderid | accountsid | so_date | amount |
+--------------+------------+------------+--------+
| 1 | 1 | 2015-12-16 | 50 |
| 2 | 1 | 2016-01-13 | 20 |
| 3 | 2 | 2015-12-14 | 10 |
| 4 | 3 | 2016-02-14 | 35 |
+--------------+------------+------------+--------+
As you can see, is a 1-N relation where Accounts has many Salesorders and Salesorder has 1 Account.
I need to retrieve "old" Accounts where are not active anymore. For example, If some Account dont have Salesorder in 2016 is an inactive Account.
So, in this example the result will be ONLY Rachel.
How can i retrieve this? I think its the "opposite" of between but I cant figure how to do it...
Thanks.
PS. Despite the title I can get this without INNER JOIN.
You're looking to effect an anti-join, for which there are three possibilities in MySQL:
Using NOT IN:
SELECT a.*
FROM Accounts a
WHERE a.accountsid NOT IN (
SELECT so.accountsid
FROM `Sales Orders` so
WHERE so.so_date >= '2016-01-01'
)
Using NOT EXISTS:
SELECT a.*
FROM Accounts a
WHERE NOT EXISTS (
SELECT *
FROM `Sales Orders` so
WHERE so.accountsid = a.accountsid
AND so.so_date >= '2016-01-01'
)
Using an outer JOIN:
SELECT a.*
FROM Accounts a LEFT JOIN `Sales Orders` so
ON so.accountsid = a.accountsid
AND so.so_date >= '2016-01-01'
WHERE so.accountsid IS NULL
why do you need to use only inner join? inner join is for cases you have data matching on two tables but in this case you don't you need to be using a subquery with either "not in" or "not exists"
What you want is to get the ids that didn´t make any order, so get the ids that made some order and the rest of them are the ones that didn´t make orders.
It should be something like this SELECT * FROM Accounts WHERE accountsid NOT IN (SELECT accountsid FROM Sales Orders WHERE so_date > your_date)

Mysql join select max for all record

I am unable to map the record as my expectation.
Doc Table
-------+-------------------
doc_id | doc_title
-------+-------------------
1 | My book
-------+-------------------
2 | My sec Book
--------------------------
Doc details Table
-----------+--------------+-----------------------
fk_doc_id | doc_version | submit_date
-----------+--------------+-----------------------
1 | 1 | 2015-10-25 14:32:01
-----------+--------------+-----------------------
1 | 2 | 2015-10-26 13:00:01
-----------+--------------+-----------------------
1 | 3 | 2015-10-27 09:00:00
--------------------------+-----------------------
2 | 1 | 2015-10-25 11:15:01
-----------+--------------+-----------------------
2 | 2 | 2015-10-26 10:00:00
--------------------------+-----------------------
Question: How do I join this two tables to get each documents with the latest version doc info? even though I get the latest version but the row info which is not correct.
So far I have tried this query
SELECT *, max(doc_version) AS latest_version
FROM d_doc
JOIN d_doc_dtl ON d_doc.doc_id = d_doc_dtl.fk_doc_id
GROUP BY d_doc.doc_id;
My expected result is
--------+--------------+----------------+--------------------
doc_id | doc_title | latest_version | submit_date
--------+--------------+----------------+--------------------
1 | My book | 3 | 2015-10-27 09:00:00
--------+--------------+----------------+--------------------
2 | My sec book | 2 | 2015-10-26 10:00:00
----------------------------------------+--------------------
but my result is
--------+--------------+----------------+--------------------
doc_id | doc_title | latest_version | submit_date
--------+--------------+----------------+--------------------
1 | My book | 3 | 2015-10-25 14:32:01
--------+--------------+----------------+--------------------
2 | My sec book | 2 | 2015-10-25 11:15:01
----------------------------------------+--------------------
NOTE: the submit_date which is no correct.
SELECT d_doc.doc_id, d_doc.doc_title, max_table.latest_version
FROM d_doc JOIN (
select fk_doc_id, max(doc_version) as latest_version from d_doc_dtl group by fk_doc_id
) as max_table ON d_doc.doc_id = max_table.fk_doc_id
This query should work as you expect. It selects latest document versions in inner subquery and than joins it with documents.
SELECT d.doc_id,
d.doc_title,
dtl.doc_version latest_version,
dtl.submit_date
FROM d_doc d
INNER JOIN (SELECT dt.*
FROM d_doc_dtl dt
INNER JOIN (SELECT fk_doc_id, MAX(doc_version) doc_version
FROM d_doc_dtl
GROUP BY fk_doc_id) dm
ON dt.fk_doc_id = dm.fk_doc_id
AND dt.doc_version = dm.doc_version) dtl
ON d.doc_id = dtl.fk_doc_id
You get wrong results because you selected only max(version), but date as it is not in group by clause can contain any value. First you need to get records containing latest version as shown above.
Easy, instead of
SELECT *, max(doc_version) AS latest_version
Use this
SELECT d_doc.*, max(doc_version) AS latest_version
What you were doing by selecting * is getting all the results after the table is joined and you only wanted the original table results.
select * from doc_table , doc_version where exists( select
max(version_id)
from
doc_version vert
where
(doc_table .DOC_ID = vert.VERSION_DOC_ID) ) group by doc_id;
You can try something like this.

Finding the MIN value that appears for each unique value in either of two other columns

Given the following (simplified) tables:
People p
id name registered
-----------------------------------
1 Geoff 2011-03-29 12:09:08
2 Phil 2011-04-29 09:03:54
3 Tony 2011-05-29 21:22:23
4 Gary 2011-06-21 22:56:08
...
Items i
date p1id p2id
----------------------------------------
2011-06-29 20:09:44 1 2
2011-06-26 10:45:00 1 3
2011-06-23 12:22:43 2 3
2011-06-22 13:07:12 2 4
...
I'd like:
The earliest single i.date that each p.id appears in either column p1id or p2id; or p.registered if they feature in neither.
So far, I've tried:
CREATE TEMPORARY TABLE temp (id INT);
INSERT INTO temp (id)
SELECT DISTINCT u FROM (
SELECT p1id AS u FROM Items UNION ALL
SELECT p2id AS u FROM Items
)tt;
SELECT registered,id FROM People
WHERE id NOT IN (SELECT id FROM temp);
Which gets me as far as the second part, albeit in a fairly clumsy way; and I'm stuck on the first part beyond some sort of external, scripted iteration through all the values of p.id (ugh).
Can anyone help?
I'm on MySQL 5.1 and there's ~20k people and ~100k items.
One more solution:
SELECT id, name, IF(min_date1 IS NULL AND min_date2 IS NULL, registered, LEAST(COALESCE(min_date1, min_date2), COALESCE(min_date2, min_date1))) date FROM (
SELECT p.id, p.name, p.registered, MIN(i1.date) min_date1, MIN(i2.date) min_date2 FROM people p
LEFT JOIN items i1
ON p.id = i1.p1id
LEFT JOIN items i2
ON p.id = i2.p2id
GROUP BY id
) t;
OR this:
SELECT p.id, p.name, COALESCE(MIN(i.date), p.registered) FROM people p
LEFT JOIN (
SELECT p1id id, date FROM items
UNION ALL
SELECT p2id id, date FROM items
) i
ON p.id = i.id
GROUP BY id;
Result:
+------+-------+---------------------+
| id | name | date |
+------+-------+---------------------+
| 1 | Geoff | 2011-06-26 10:45:00 |
| 2 | Phil | 2011-06-22 13:07:12 |
| 3 | Tony | 2011-06-23 12:22:43 |
| 4 | Gary | 2011-06-22 13:07:12 |
+------+-------+---------------------+
This is tested in Postgres, but I think it ought to work in MySQL with few or no changes:
SELECT p.id,COALESCE(MIN(x.date),p.registered) AS date
FROM p
JOIN (
SELECT p.id,MIN(i.date) AS date
FROM p
JOIN i ON (p.id=i.p1id)
GROUP BY p.id
UNION
SELECT p.id,MIN(i.date) AS date
FROM p
JOIN i ON (p.id=i.p2id)
GROUP BY p.id
) AS x ON x.id = p.id
GROUP BY p.id,p.registered;
Output (given your sample data):
id | date
----+---------------------
3 | 2011-06-23 12:22:43
1 | 2011-06-26 10:45:00
2 | 2011-06-22 13:07:12
4 | 2011-06-22 13:07:12
(4 rows)