SQL Find closest timestmaps when duplicates exists - mysql

I cant find topic to my problem, so i'm asking here.
I have select:
SELECT t1.*,
t2.unixtimestamp as rj_time,
t2.response_detail as rj_error
FROM t1
LEFT JOIN table2 as t2
ON t1.id=t2.personid
AND t1.clientcode=t2.client
WHERE t1.clientcode='quouk'
AND (t1.language = 'en_GB')
ORDER BY t1.id
TABLE 1:
id clientcode language
1 quouk en_GB
2 quouk en_GB
3 quouk en_GB
TABLE 2:
id personid client language unixtimestamp response_detail
1 1 quouk en_GB 1393401000 error
2 1 quouk en_GB 1393401001 error
3 2 quouk en_GB 1393404600 error
4 2 quouk en_GB 1393404601 error
5 3 quouk en_GB 1393257900 error
6 3 quouk en_GB 1393257901 error
So if i am launching this query, it returning to me 6 rows, but the result should be 3 rows (from table 2 : 2, 4, 6 id's). If you will look into timestamps you will see a small difference between rows. That means i need to find closest dates to now. I saw a lot of solutions to use LIMIT at the end of the query, but i think it is a bit different in my case.

Assuming the timestamps are not in the future then the nearest one to now will be the latest one.
As such you can probably do this by adding a simple LEFT JOIN against a sub query:-
SELECT t1.*, t2.unixtimestamp as rj_time, t2.response_detail as rj_error
FROM t1
LEFT OUTER JOIN
(
SELECT personid, client, MAX(unixtimestamp) AS MaxTimeStamp
FROM table2
GROUP BY personid, clientcode
) Sub1
ON t1.id = Sub1.personid AND t1.clientcode = Sub1.client
LEFT OUTER JOIN table2 as t2
ON Sub1.personid=t2.personid AND Sub1.client = t2.client AND Sub1.MaxTimeStamp = t2.unixtimestamp
WHERE t1.clientcode='quouk'
AND (t1.language = 'en_GB')
ORDER BY t1.id
This gets the latest timestamp for each person / client from table2, and then joins that against table2 to get the other columns that are required (ie response_detail). If you just used MAX then you would possibly not get the correct value of response_detail as that would come from an undefined row rather than from the row that the MAX applies to.

SELECT t1.*, MAX(t2.unixtimestamp as rj_time), t2.response_detail as rj_error
FROM t1
LEFT JOIN table2 as t2 ON t1.id=t2.personid AND t1.clientcode=t2.client
WHERE t1.clientcode='quouk'
AND (t1.language = 'en_GB')
GROUP BY t1.id
ORDER BY t1.id

Related

prevent duplicate result when using self-join in mysql

I have some hotel with different hotel view for each room , and my end user when want 3 rooms for example each the room is 2 bed I have to combination the record for that , some times some fields may be duplicated and It's not important , and the user may have different room type in this situation I make example to each room have 2 bed number :
I have problem when get result :
I use self-join in "mysql" and all thing are true but some problem is have same row in this situation this is my code:
SELECT
table1.id,
table2.id,
table3.id,
table1.num_bed,
table2.num_bed,
table3.num_bed
LEFT JOIN
tour_package table2
ON table1.tour_id = table2.tour_id
AND table1.hotel_id = table2.hotel_id
AND table1.start_date = table2.start_date
LEFT JOIN
tour_package table3
ON table2.tour_id = table3.tour_id
AND table2.hotel_id = table3.hotel_id
AND table2.start_date = table3.start_date
WHERE
table1.num_bed = 2
AND table2.num_bed = 2
AND table3.num_bed = 2
the result is :
Please attention to id , the one is table1.id, two is table2.id and three is table3.id
In the result we have some result like :
1-2-1
1-1-2
and etc
I want to prevent this and have one of them , please help me
I assume the goal of the query is to list up to 3 rooms per record in the same hotel, for the same tour and dates that have 2 bed.
(I honestly do not get the point of the query because it will list all 2-bed rooms in the tour_package table.)
This means that not only 1-1-2 and 1-2-1 are duplicates, but also the 2nd 1 is a redundant information. In hotel no. 7 there are only 2 rooms that satisfy this criteria: 1 and 2.
In the join criteria I would require that a record with different id should be returned from each of the tables. This would force the query to return list of unique ids in a record.
SELECT
table1.id,
table2.id,
table3.id,
table1.num_bed,
table2.num_bed,
table3.num_bed
FROM tour_package table1
LEFT JOIN
tour_package table2
ON table1.tour_id = table2.tour_id
AND table1.hotel_id = table2.hotel_id
AND table1.start_date = table2.start_date
AND table1.id<table2.id
LEFT JOIN
tour_package table3
ON table2.tour_id = table3.tour_id
AND table2.hotel_id = table3.hotel_id
AND table2.start_date = table3.start_date
AND table2.id<table3.id
WHERE
table1.num_bed = 2
AND table2.num_bed = 2
AND table3.num_bed = 2
However, the above query can potentially still return redundant data if there are at least 2 rooms with the above criteria in a hotel. Assuming the 2 rooms have the ids 1 and 2, the query would return 1, 2, null and 2, null, null. To overcome this issue, I would just simply write:
select id, hotel_id from tour_package
where tour_package.num_bed=2
order by tour_id, hotel_id, start_date
The reason: even your on query will show all 2-bed rooms in your tour_package table.

Join Two Tables and Replace Values Where Conditions Meet

I'm trying to come with an expression to join two tables (the first two) to get something like the third one.
I want to SELECT 'Sitepage' and 'Medium' and JOIN the first two tables ON the rows where the RIGHT 5 characters are matching between 'Sitepage' and 'Campaign ID'. Additionally, IF there is a match, THEN 'Program' will REPLACE 'Medium'. What would be the Syntax?
Sitepage | Medium
xyz.com/campaign=12345 | A
xyz.com/campaign=23456 | C
Campaign ID | Program
12345 | B
Sitepage | Medium
xyz.com/campaign=12345 | B
xyz.com/campaign=23456 | C
http://i.stack.imgur.com/pq35n.png
I based my answer off of #Juan's, but I had to make some adjustments to get it to work.
SELECT
SitePage, COALESCE(t2.Program, t1.Medium) as Medium
FROM Table1 t1
LEFT JOIN Table2 t2
ON RIGHT(t1.Sitepage, 5) = COALESCE(t2.`Campaign ID`, -1);
#Abhik was heading in the right direction too. It's more generic than the one above, which assumes that the last 5 characters of SitePage will be the only pertinent ones. With that said, I would have gone with...
SELECT
SitePage, COALESCE(t2.Program, t1.Medium) as Medium
FROM Table1 t1
LEFT JOIN Table2 t2
ON SUBSTRING_INDEX(t1.Sitepage,'=',-1)
= COALESCE(t2.`Campaign ID`, -1);
SQL Fiddle example
You can use substring_index and then update by join
update table1 t1
join table2 t2 on t2.`Campaign ID` = substring_index(t1.`Sitepage`,'=',-1)
set t1.`Medium` = t2.`Program`
SELECT SitePage, ISNULL(t2.Program, t1.Medium) as Medium
FROM Table1 t1
LEFT JOIN Table2 t2 ON RIGHT(t1.Medium, 5) = t2.CampaignId
That should do the trick. Left Join on the expresion you want, when there is a match, Program will not be null so you can pick it up, otherwise pick medium. If your table2 allows null on Program you may need to tweak this.

mysql Left Join on POINT datatype

I have two table that each of them have a column with point (spatial) datatype like this :
Table 1 :
id latlng
------------------------------
1 POINT(35.72036 51.42124)
2 POINT(32.74446 53.42124)
3 POINT(31.78676 51.44564)
4 POINT(32.73436 54.42124)
Table 2:
id latlng
------------------------------
1 POINT(35.719 51.4221)
2 POINT(35.72036 51.42124)
3 POINT(32.74446 53.42124)
4 POINT(31.78676 51.44564)
5 POINT(32.73436 54.42124)
6 POINT(35.72379 51.4144)
Now i want to join these two table in together with LEFT JOIN statement on Table 2
i wrote this query but it returns 24 rows! i should be 6 rows like table 2.
SELECT * FROM Table2 LEFT JOIN Table1 ON Table2.latlng = Table1.latlng
is there any way to resolve this problem & just get 6 rows?
i think you forgot GROUP BY
try this
SELECT * FROM Table2
LEFT JOIN Table1
ON Table2.latlng = Table1.latlng
GROUP BY Table2.id

How to left join or inner join a table itself

I have this data in a table, for instance,
id name parent parent_id
1 add self 100
2 manage null 100
3 add 10 200
4 manage null 200
5 add 20 300
6 manage null 300
How can I left join or inner join this table itself so I get this result below?
id name parent
2 manage self
4 manage 10
6 manage 20
As you can I that I just want to query the row with the keyword of 'manage' but I want the column parent's data in add's row as the as in manage's row in the result.
Is it possible?
EDIT:
the simplified version of my actual table - system,
system_id parent_id type function_name name main_parent make_accessible sort
31 30 left main Main NULL 0 1
32 31 left page_main_add Add self 0 1
33 31 left page_main_manage Manage NULL 0 2
my actual query and it is quite messy already...
SELECT
a.system_id,
a.main_parent,
b.name,
b.make_accessible,
b.sort
FROM system AS a
INNER JOIN -- self --
(
SELECT system_id, name, make_accessible, sort
FROM system AS s2
LEFT JOIN -- search --
(
SELECT system_id AS parent_id
FROM system AS s1
WHERE s1.function_name = 'page'
) AS s1
ON s1.parent_id = s2.parent_id
WHERE s2.parent_id = s1.parent_id
AND s2.system_id != s1.parent_id
ORDER BY s2.sort ASC
) b
ON b.system_id = a.parent_id
WHERE a.function_name LIKE '%manage%'
ORDER BY b.sort ASC
result I get currently,
system_id main_parent name make_accessible sort
33 NULL Main 0 1
but I am after this,
system_id main_parent name make_accessible sort
33 self Main 0 1
You just need to reference the table twice:
select t1.id, t1.name, t2.id, t2.name
from TableA t1
inner join TableA t2
on t1.parent_id = t2.Id
Replace inner with left join if you want to see roots in the list.
UPDATE:
I misread your question. It seems to me that you always have two rows, manage one and add one. To get to "Add" from manage:
select system.*, (select parent
from system s2
where s2.parent_id = system.parent_id
and s2.name = 'add')
AS parent
from system
where name = 'manage'
Or, you might split the table into two derived tables and join them by parent_id:
select *
from system
inner join
(
select * from system where name = 'add'
) s2
on system.parent_id = s2.parent_id
where system.name = 'manage'
This will allow you to use all the columns from s2.
Your data does not abide to a child-parent hierarchical structure. For example, your column parent holds the value 10, which is not the value of any id, so a child-parent association is not possible.
In other words, there's nothing that relates the record 2,manage,null to the record 1,add,self, or the record 4,manage,null to 3,add,10, as you intend to do in your query.
To represent hierarchical data, you usually need a table that has a foreign key referencing it's own primary key. So your column parent must reference the column id, then you can express a child-parent relationship between manage and add. Currently, that's not possible.
UPDATED: Joining by parent_id, try:
select m.id, m.name, a.parent
from myTable m
join myTable a on m.parent_id = a.parent_id and a.name = 'add'
where m.name = 'manage'
Change the inner join to a left join if there may not be a corresponding add row.

mySQL query help needed

I have two tables:
t1
------------------
inv_ID
inv_memID
inv_projID
t2
------------------
is_ID
is_msgID
is_contID
I need to get all t2.is_contID into an array where
inv_projID = 5
t2.is_msgID = t1.inv_ID and
t1.inv_memID = 1
Seem pretty straight forward but I'm stuck... Tried this:
SELECT t2.is_contID
INNER JOIN t1 ON (t1.inv_ID = t2.is_msgID)
FROM t2
WHERE t1.inv_projID = 5
AND t1.inv_memID = 1
What am I missing?
FROM comes before JOIN.
SELECT t2.is_contID
FROM t2
INNER JOIN t1 ON (t1.inv_ID = t2.is_msgID)
WHERE t1.inv_projID = 5
AND t1.inv_memID = 1
SQL is very fussy about the order of the keywords.
The correct order is:
SELECT
FROM
JOIN
WHERE
HAVING
GROUP BY
ORDER
LIMIT <<-- MySQL only, other DB's user other keywords in other places.