How to get unique latest updated database? - mysql

I was trying to retrieve where i want to get data based on unique id and But the latest one.
ie,
id customer_name uniqueId
1 x 1123
2 y 1123
3 z 1124
4 m 1125
5 n 1125
expected output after query:
id customer_name uniqueId
1 y 1123
2 z 1124
3 n 1125
I used the following statements but couldn't get the expected answer:
$customers = DB::table('customers')
->select('uniqueId','customer_name','id','created_at')
->orderBy('created_at','desc')
->groupBy('uniqueId')
->get();
Can anyone suggest me the right answer?

I think it should be like:
SELECT [id],[customer_name],[uniqueId]
FROM [Table name]
WHERE [id]= 2 OR ID = 3 OR ID = 5
Or with the IN clause
where id in (id1,id2.........long list)
If you really want to change the id to (1,2,3) you can always export this data somewhere else like new table i.e. and do the update function.
i.e.
UPDATE Your Table Here
SET id = 1
WHERE [unique_id]=1123
etc.
Cheers,
Kacper

I solved your problems. It would be some complex query. But it solved your problems. It is raw query. I run raw query by laravel query builder. If you get more simple query, then let us know.
$sql = "
SELECT p.`id`,p.`customer_name`,p.`uniqueId`
FROM
(
SELECT MAX(created_at) AS created_at
FROM `customers`
GROUP BY `uniqueId`
) t
LEFT JOIN `customers` p ON t.created_at = p.`created_at`
"
$customers = DB::select($sql);

Related

How to get sorted result within INNER JOIN on joined table

I'm trying to get results from a join of 2 tables. Typically, not an issue, but I'm banging my head on this one. Basically, table1 (sales_dealers) is joined with table2 (sales_dealerEvents). Normally, easy-peasy. The problem is that I want to only get records from table2 if there are only 2 events (why I added the HAVING). But I need to get the value of the second event. With my query now, I can only get the value of the first event. It's like I need an ORDER BY EventID DESC on the joined table. It giving me ASC by default with this query.
Here is my query:
SELECT e.EventAction
, d.DealerID
, d.AgentID
, d.DealerName
, d.Email
, SUBSTRING_INDEX(d.PrimaryContactName, ' ', 1) AS FirstName
, d.State
, COUNT(e.EventID) AS EventCount
FROM sales_dealers d
JOIN sales_dealerEvents e
ON d.DealerID = e.DealerID
WHERE d.AgentID = 1
AND d.StatusID = 3
AND d.Email REGEXP '^[a-zA-Z0-9][a-zA-Z0-9._-]*#[a-zA-Z0-9][a-zA-Z0-9._-]*\\.[a-zA-Z]{2,4}$'
GROUP
BY d.DealerID
HAVING COUNT(e.EventID) = 2
ORDER
BY e.EventID DESC
Here is my Schema for the two tables (mysql version 5.7.27 )
sales_dealers
------------------
DealerID (int PK)
StatusID (int)
AgentID (int)
DealerName (varchar)
Email (varchar)
PrimaryContactName (varchar)
State (varchar)
sales_dealerEvents
------------------
EventID (int PK)
DealerID (FK)
AgentID (FK)
EventDateTime (datetime)
EventAction (longtext)
Here is sample data. Currently, the above query returns this:
Prospect Entry 784 1 Dealer Name One sales#dealer.com CA 2
Prospect Entry 782 1 Some other dealer hello#dealer.com MT 2
Prospect Entry 781 1 Dealer Store contact#dealer.com OK 2
I would like it to return this:
Initial Contact 784 1 Dealer One sales#dealer.com CA 2
Initial Contact 782 1 Some other dealer hello#dealer.com MT 2
Initial Contact 781 1 Dealer Store contact#dealer.com OK 2
Here is the same sample data of but showing the relationship of the one to many in sales_dealerEvents
sales_dealer
784 Dealer Name One
sales_dealerEvents
1000 784 1 Prospect Entry 2020-06-02 01:00:00
1010 784 1 Initial Contact 2020-07-03 01:00:00
I'm feeling I might have to do this in a subquery to sort the event so the second event is first. Not sure. I might also need to match criteria of that second event too.
UPDATE - Here is my SQL fiddle
http://sqlfiddle.com/#!9/ef6f2c/2
As you can see with the fiddle.. all event records returned are 'prospect entry'.. which were the first entries for 'events' for those. Each have 2. The second is 'Initial Contact'. Their date and EventID is after the 'prospect entry'.
Hope the below query helps and you can see the demo here: http://sqlfiddle.com/#!9/ef6f2c/37/0
SELECT
EventAction,
DealerID,
AgentID,
DealerName,
Email,
FirstName,
State,
EventID
from
(
SELECT
e.EventAction,
d.DealerID,
d.AgentID,
d.DealerName,
d.Email,
SUBSTRING_INDEX(d.PrimaryContactName, ' ', 1) AS FirstName,
d.State,
e.EventID as EventID
FROM
sales_dealers d
JOIN
sales_dealerEvents e
ON d.DealerID = e.DealerID
WHERE
d.AgentID = 1
AND d.StatusID = 3
AND d.Email REGEXP '^[a-zA-Z0-9][a-zA-Z0-9._-]*#[a-zA-Z0-9][a-zA-Z0-9._-]*\\.[a-zA-Z]{2,4}$'
ORDER BY
e.EventID DESC
)
a
GROUP BY
DealerID
HAVING
COUNT(EventID) = 2
This sounds like you want window functions:
select . . .
from sales_dealers d join
(select e.*,
row_number() over (partition by e.DealerID order by e.EventDateTime) as seqnum
from sales_dealerEvents e
) e
on e.DealerID = d.DealerID and e.seqnum = 2
where . . .
Note this gets data from the second event even if there are more than two events. That seems consistent with the question, but it is easy enough to use count(*) as a window function to do further filtering.

Nested queries and Join

As a beginner with SQL, I’m ok to do simple tasks but I’m struggling right now with multiple nested queries.
My problem is that I have 3 tables like this:
a Case table:
id nd date username
--------------------------------------------
1 596 2016-02-09 16:50:03 UserA
2 967 2015-10-09 21:12:23 UserB
3 967 2015-10-09 22:35:40 UserA
4 967 2015-10-09 23:50:31 UserB
5 580 2017-02-09 10:19:43 UserA
a Value table:
case_id labelValue_id Value Type
-------------------------------------------------
1 3633 2731858342 X
1 124 ["864","862"] X
1 8981 -2.103 X
1 27 443 X
... ... ... ...
2 7890 232478 X
2 765 0.2334 X
... ... ... ...
and a Label table:
id label
----------------------
3633 Value of W
124 Value of X
8981 Value of Y
27 Value of Z
Obviously, I want to join these tables. So I can do something like this:
SELECT *
from Case, Value, Label
where Case.id= Value.case_id
and Label.id = Value.labelValue_id
but I get pretty much everything whereas I would like to be more specific.
What I want is to do some filtering on the Case table and then use the resulting id's to join the two other tables. I'd like to:
Filter the Case.nd's such that if there is serveral instances of the same nd, take the oldest one,
Limit the number of nd's in the query. For example, I want to be able to join the tables for just 2, 3, 4 etc... different nd.
Use this query to make a join on the Value and Label table.
For example, the output of the queries 1 and 2 would be:
id nd date username
--------------------------------------------
1 596 2016-02-09 16:50:03 UserA
2 967 2015-10-09 21:12:23 UserB
if I ask for 2 different nd. The nd 967 appears several times but we take the oldest one.
In fact, I think I found out how to do all these things but I can't/don't know how to merge them.
To select the oldest nd, I can do someting like:
select min((date)), nd,id
from Case
group by nd
Then, to limit the number of nd in the output, I found this (based on this and that) :
select *,
#num := if(#type <> t.nd, #num + 1, 1) as row_number,
#type := t.nd as dummy
from(
select min((date)), nd,id
from Case
group by nd
) as t
group by t.nd
having row_number <= 2 -- number of output
It works but I feel it's getting slow.
Finally, when I try to make a join with this subquery and with the two other tables, the processing keeps going on for ever.
During my research, I could find answers for every part of the problem but I can't merge them. Also, for the "counting" problem, where I want to limit the number of nd, I feel it's kind of far-fetch.
I realize this is a long question but I think I miss something and I wanted to give details as much as possible.
to filter the case table to eliminate all but oldest nds,
select * from [case] c
where date = (Select min(date) from case
where nd = c.nd)
then just join this to the other tables:
select * from [case] c
join value v on v.Case_id = c.Id
join label l on l.Id = v.labelValue_id
where date = (Select min(date) from [case]
where nd = c.nd)
to limit it to a certain number of records, there is a mysql specific command, I think it called Limit
select * from [case] c
join value v on v.Case_id = c.Id
join label l on l.Id = v.labelValue_id
where date = (Select min(date) from [case]
where nd = c.nd)
Limit 4 -- <=== will limit return result set to 4 rows
if you only want records for the top N values of nd, then the Limit goes on a subquery restricting what values of nd to retrieve:
select * from [case] c
join value v on v.Case_id = c.Id
join label l on l.Id = v.labelValue_id
where date = (Select min(date) from [case]
where nd = c.nd)
and nd In (select distinct nd from [case]
order by nd desc Limit N)
So finally, here is what worked well for me:
select *
from (
select *
from Case
join (
select nd as T_ND, date as T_date
from Case
where nd in (select distinct nd from Case)
group by T_ND Limit 5 -- <========= Limit of nd's
) as t
on Case.nd = t.T_ND
where date = (select min(date)
from Case
where nd = t.T_ND)
) as subquery
join Value
on Value.context_id = subquery.id
join Label
on Label.id = Value.labelValue_id
Thank you #charlesbretana for leading me on the right track :).

Return matching values, exclude the ones that aren't matching, remove duplicates MYSQL

I have a problem that I can't seem to solve. I have a table that tracks userID's and app ID's. The table looks like this:
Library:
ID userID appID
1 1 11122
2 1 65324
3 1 43435
4 2 43435
5 2 50645
6 2 34343
7 4 11122
8 4 55343
The query should do the following:
Return all appID values that selected users have in common. (If user 4 and user 1 are selected and both have the app 11122 it should show app 11122)
Exclude the ones that aren't matching (Remove the ones they don't have in common. In this example it would be remove ids (55343, 65324 and 43435)
Remove duplicate results (It should not list the same app twice. So appID 11122 should show only once)
Here's a PHP example of what I'm trying to do:
$array1 = array("a" => "green", "red", "blue");
$array2 = array("b" => "green", "yellow", "red");
$result = array_intersect($array1, $array2);
Results would be "green" and "red"
Is this possible through MySQL?
you could try this:
select a.appID from Library a
inner join
(select appID,count(ID) as ctr from Library where userID in(1,4) group by appID) b on b.appID = a.appID
where b.ctr > 1
group by a.appID;
sql fiddle
update:
i'm not sure if you want to view the common user ids into 1 column only
select a.appID,group_concat(a.userID) as user_ids from Library a
inner join
(select appID,count(ID) as ctr from Library where userID in(1,4) group by appID) b on b.appID = a.appID
where b.ctr > 1
group by a.appID;
SQL Fiddle
I'm not positive I completely understand your question, but it sounds like you want to return userID 1 and 2 because they are associated with the same appID (actually twice). If so, then this should work:
select L.userID, L.appID
from Library L
join (
select appID
from Library
group by appId
having count(distinct userID) > 1
) L2 on L.appID = L2.appID
SQL Fiddle Demo
And if you just need the unique userID, remove appID from the above query and add DISTINCT.

specific mysql select query

today i need your help to get an specific sql select query.
i have following table:
and after a specific query regarding a specific id (in this case id 1) i wanna have a result like this:
user_id (an alias for the id_sender/id_recipient), date (maybe a max function, cause i wanna have the latest date to group), messages (a count function to the messages):
10 | 2012-01-14 09:10:05 | 4
11 | 2012-01-13 13:52:49 | 1
13 | 2012-01-13 20:01:17 | 1
14 | 2012-01-14 09:20:17 | 1
i tryed a lot but dont get the exact results - so my approach was something like this:
SELECT `id_recipient`, `id_sender`, MAX(`date`) AS `date`, COUNT(*) AS `messages` FROM `table` WHERE `id_recipient` = 1 OR `id_sender` = 1 GROUP BY `id_recipient`, `id_sender`
but then i get this result:
its not so bad but as u can see the 4th line should be included in the results of the first one.
i hope u got me. feel free to ask if smth is not clear.
thanks in advance,
greetings
Ok, so since we know the value for id_recipient, we can use some math to trick SQL into getting this nasty query done.
Let n be the id value of the person of interest.
We know that the pairing of id_recipient and id_sender will ALWAYS include the user with id value n. Based on the where clause.
Therefore, id_recipient + id_sender == n + id_otherPerson is true.
The resulting query will be very similar to this.
(It's been a while, but I don't think I have any syntax problems)
SELECT (`id_recipient` + `id_sender` - n) AS `id_otherPerson`,
MAX(`date`) AS `date`, COUNT(*) AS `messages`
FROM `table`
WHERE `id_recipient` = n XOR `id_sender` = n
GROUP BY `id_otherPerson`;
Edit: I've changed it to an XOR, so if person n messages person n, it won't cause all values to be incremented by the number of times n has messaged themself.
What about this?
SELECT user_id, MAX(date), COUNT(*)
FROM (
SELECT id_recipient AS 'user_id', date
FROM table
WHERE id_recipient <> 1 AND id_sender = 1
UNION
SELECT id_sender AS 'user_id', date
FROM table
WHERE id_recipient = 1 AND id_sender <> 1
) AS tbl
GROUP BY user_id
It assumes you want to use id_recipient if the id_sender is 1 and id_sender if id_recipient is 1.
I believe the output you want should be as below
10 | 2012-01-13 20:01:17 | 3
11 | 2012-01-13 13:52:49 | 1
13 | 2012-01-13 20:01:17 | 1
I'm saying as you are mixing id_recipient and id_sender

Mysql combine rows?

I have a table with itemid|fieldid|value and i'm trying to setup a query that will combine some data and return a mathc percentage along with the result. for example, some data could be
itemid fieldid value
19 193 1
45 193 1
37 201 6
25 201 1
45 201 6
19 201 6
19 201 5
Now i want for example, to get all the rows with fieldid = 193 AND value = 1 as well as the rows with fieldid = 201 AND value = 6. The ideal result would be something like :
itemid, percentage getting 100% for all itemids which match both conditions and 50% for all that match one. I have this query working for doing the above over multiple columns but it will not work here
select id,user_class,admin, (
if (admin = 1,1,0)+
if (user_class = 'SA',1,0)
)/2*100 as the_percent
from users
WHERE
admin = 1 OR user_class = 'P'
GROUP BY id
order by the_percent DESC
Also i got the following for absolute matching
SELECT users.id FROM users WHERE
users.id IN
(
SELECT DISTINCT itemid FROM extra_field_values
INNER JOIN (SELECT DISTINCT itemid FROM extra_field_values WHERE fieldid = 201 AND value = 6 ) a1 USING (itemid)
INNER JOIN (SELECT DISTINCT itemid FROM extra_field_values WHERE fieldid = 193 AND value = 1 ) a2 USING (itemid)
)
but combining the two seems to be a bit of a puzzle to me
I think you might be able to make use of a UNION and selecting from a table subquery to make this happen. Perhaps something along the lines of:
SELECT itemid, count(*)/2*100 AS percent FROM
( SELECT itemid FROM extra_field_values WHERE fieldid = 201 AND value = 6
UNION ALL
SELECT itemid FROM extra_field_values WHERE fieldid = 193 AND value = 1 ) AS t
GROUP BY itemid;
It's been a while since I've done anything complex in mysql, and I threw this together in notepad so my syntax could be off :) But basically we create a view of the matching ids, then from that table create our statistics. (You'll also want to do some performance evaluation as well to see how it stacks up compared to doing multiple queries as well).