Combine one table with meta data in another table - mysql

I am trying to get all result combined from two tables. Currently, I am making two requests to get a table, but I believe there are many good ways to combine the result. I've tried using join with this query
USE test;
SELECT * FROM main INNER JOIN main_meta ON main.id = main_meta.ref WHERE main.id = 1;
but ended up having repeating data like this:
id
body
title
time
id
ref
data
1
happy birthday to you !
Birthday Celebration
2021-10-14 06:34:36
1
1
first_name: ABC
1
happy birthday to you !
Birthday Celebration
2021-10-14 06:34:36
2
1
last_name: DEF
1
happy birthday to you !
Birthday Celebration
2021-10-14 06:34:36
3
1
email: abc#xyz.co
There is one main entry which will have any number of metadata for that reason main post is repeating multiple times now. I wanted to get main data once and multiple metadata in result.
The result I'm looking for is this:
id
body
title
time
id
ref
data
1
happy birthday to you !
Birthday Celebration
2021-10-14 06:34:36
1
1
first_name: ABC
2
1
last_name: DEF
3
1
email: abc#xyz.co

If you don't mind having data column with combined values, then you might want to consider using GROUP_CONCAT(). So a query like this:
SELECT main.id, main.body, main.title, main.time,
GROUP_CONCAT(main_meta.data)
FROM main
INNER JOIN main_meta
ON main.id = main_meta.ref
WHERE main.id = 1
GROUP BY id, body, title, time;
.. will return you result like this:
id
body
title
time
GROUP_CONCAT(main_meta.data)
1
happy birthday to you !
Birthday Celebration
2021-10-14 06:34:36
first_name: ABC,last_name: DEF,email: abc#xyz.co
If you want the data column values to be separated (like in your question edit), then this suggestion (works with MySQL v8+ or MariaDB v10.2+ and above):
SELECT CASE WHEN rn=1 THEN id ELSE '' END id,
CASE WHEN rn=1 THEN body ELSE '' END body,
CASE WHEN rn=1 THEN title ELSE '' END title,
CASE WHEN rn=1 THEN time ELSE '' END time,
data
FROM
(SELECT main.id, main.body, main.title, main.time, main_meta.data,
ROW_NUMBER() OVER (PARTITION BY main.id ORDER BY main_meta.id) rn
FROM main
INNER JOIN main_meta
ON main.id = main_meta.ref
WHERE main.id = 1) v;
Although it is possible, I'm not sure if there's any reason to make it like that unless it's only for viewing purposes. And if the end result is going to be shown on a webpage (e.g. for web report view) then, it's better to do the second option in the application code rather than from the MySQL query.
Anyway, here's a demo fiddle for reference

Related

MySQL check if a condition is true from last to start and if stopped return

I really love to know how this is possible without doing a for loop.My way is lame,I check the last then take the previous check again and add this values to an array and when the condition wasn't true anymore I return the array.This is not pure sql and uses php for loop so it's not very performant,I need to do this with sql.Example:
chatTable:
from_id to_id msg time
2 1 Hi 2 days ago(as timestamp)
1 2 Hello yesterday
1 2 How you doing? today
So here we are going to take all the messages that id 1 sent from the latest until It's not him anymore.
1->2 How you doing = (true)
1->2 Hello = (true)
2->1 Hi = (false)
so
return
1->2 How you doing
1->2 Hello
First way is to order the recrods in desc order of timestamp. Then look for patterns in your data such that the next_from_id is same as that of the current_from_id.
If they are different then ignore.
If this looks correct the following can be done
select * from (
select from_id
,to_id
,timestamp
,lead(from_id) over(order by timestamp desc) as next_frm_id
from chatTable
)x
where x.from_id = x.next_frm_id
If I understand correctly, you want the last set of messages that are for from_id = 1. That would be:
select ct.*
from chatTable ct
where ct.from_id = 1 and
ct.timestamp > (select max(ct2.timestamp)
from chatTable ct2
where ct2.from_id <> 1
);
This assumes that the most recent message if from id 1.

Selecting rows until a column value isn't the same

SELECT product.productID
, product.Name
, product.date
, product.status
FROM product
INNER JOIN shelf ON product.sheldID=shelf.shelfID
WHERE product.weekID = $ID
AND product.date < '$day'
OR (product.date = '$day' AND shelf.expire <= '$time' )
ORDER BY concat(product.date,shelf.expire)
I am trying to stop the SQL statement at a specific value e.g. bad.
I have tried using max-date, but am finding it hard as am making the time stamp in the query. (Combining date/time)
This example table shows that 3 results should be returned and if the status "bad" was the first result than no results should be returned. (They are ordered by date and time).
ProductID Date status
1 2017-03-27 Good
2 2017-03-27 Good
3 2017-03-26 Good
4 2017-03-25 Bad
5 2017-03-25 Good
Think I may have fixed it, I added this to my while loop.
The query gives the results in order by present to past using date and time, this while loop checks if the column of that row is equal to 'bad' if it is does something (might be able to use an array to fill it up with data). If not than the loop is broken.
I know it doesn't seem ideal but it works lol
while ($row = mysqli_fetch_assoc($result)) {
if ($row['status'] == "bad") {
$counter += 1;
}
else{
break;}
I will provide an answer just with your output as if it was just one table. It will give you the main ideia in how to solve your problem.
Basically I created a column called ord that will work as a row_number (MySql doesn't support it yet AFAIK). Then I got the minimum ord value for a bad status then I get everything from the data where ord is less than that.
select y.*
from (select ProductID, dt, status, #rw:=#rw+1 ord
from product, (select #rw:=0) a
order by dt desc) y
where y.ord < (select min(ord) ord
from (select ProductID, status, #rin:=#rin+1 ord
from product, (select #rin:=0) a
order by dt desc) x
where status = 'Bad');
Result will be:
ProductID dt status ord
-------------------------------------
1 2017-03-27 Good 1
2 2017-03-27 Good 2
3 2017-03-26 Good 3
Also tested with the use case where the Bad status is the first result, no results will be returned.
See it working here: http://sqlfiddle.com/#!9/28dda/1

Append string to a record's specified column after SELECT command

I have an sql command that returns me a list of duplicated items (in my MySQL database), only two columns, one for the duplicated value and one for the count of duplicated records.
SELECT title, COUNT(*) c FROM posts GROUP BY title HAVING c > 1
title c
---------------
title_1 2
title_a 2
title_b 2
I assume one result looks like this:(and it's an array of arrays)
objId title
------------
1 title_1
2 title_1
So my goal is to append a string to the second item of a result in the array of the duplicated record's like this:
objId title
------------
1 title_1
2 title_1_2
I've found a solution to update the record, but I don't have an idea how could I loop through the results that I get after the first sql command so I can't utilize it in practice.
UPDATE posts SET title = CONCAT(IFNULL(title,''), ' 2');
In pseudo code I would do something like this to create the new string for the title:
result[1].title = (oldTitleString," 2");
save result[1];
I'm new in sql and don't really know about the possibilities, maybe there would be an easier way to do it, so I would really appreciate if somebody could show me how can I get the second record from the duplicated item and extend it with another string.
My solution:
SELECT `objId`,`title`,
(SELECT CONCAT(`title`, '_', `po`.`objId`)
FROM `posts` `p`
WHERE `title` = `po`.`title` && `p`.`objId` < `po`.`objId` LIMIT 1) AS `title_custom`
FROM `posts` `po`
Here is sample fiddle:
http://sqlfiddle.com/#!9/a4164/8
Query looks like this:
select id, title,
concat(title,'_',
(select count(*) from posts p2 where p2.title = p1.title and p2.id <= p1.id)),
title,
count(*) c
from posts p1
group by title
having c > 1

How to do this query against MySQL database table?

I was given a task to show the CPU usage trend as part of a building process which also do regression test.
Each individual test case run has a record in the table RegrCaseResult. The RegrCaseResult table looks something like this:
id projectName ProjectType returnCode startTime endTime totalMetrics
1 'first' 'someType' 16 'someTime' 'someOtherTime' 222
The RegrCaseResult.totalMetrics is a special key which links to another table called ThreadMetrics through ThreadMetrics.id.
Here is how ThreadMetrics will look like:
id componentType componentName cpuTime linkId
1 'Job Totals' 'Job Totals' 'totalTime' 34223
2 'parser1' 'parser1' 'time1' null
3 'parser2' 'generator1' 'time2' null
4 'generator1' 'generator1' 'time3' null
------------------------------------------------------
5 'Job Totals' 'Jot Totals' 'totalTime' 9899
...
The rows with the compnentName 'Job Totals' is what the totalMetrics from RegrCaseResult table will link to and the 'totalTime' is what I am really want to get given a certain projectType. The 'Job Totals' is actually a summation of the other records - in the above example, the summation of time1 through time3. The linkId at the end of table ThreadMetrics can link back to RegrCaseResult.id.
The requirements also states I should have a way to enforce the condition which only includes those projects which have a consistent return code during certain period. That's where my initial question comes from as follows:
I created the following simple table to show what I am trying to achieve:
id projectName returnCode
1 'first' 16
2 'second' 16
3 'third' 8
4 'first' 16
5 'second' 8
6 'first' 16
Basically I want to get all the projects which have a consistent returnCode no matter what the returnCode values are. In the above sample, I should only get one project which is "first". I think this would be simple but I am bad when it comes to database. Any help would be great.
I tried my best to make it clear. Hope I have achieved my goal.
Here is an easy way:
select projectname
from table t
group by projectname
having min(returncode) = max(returncode);
If the min() and max() values are the same, then all the values are the same (unless you have NULL values).
EDIT:
To keep 'third' out, you need some other rule, such as having more than one return code. So, you can do this:
select projectname
from table t
group by projectname
having min(returncode) = max(returncode) and count(*) > 1;
select projectName from projects
group by projectName having count(distinct(returnCode)) = 1)
This would also return projects which has only one entry.
How do you want to handle them?
Working example: http://www.sqlfiddle.com/#!2/e7338/8
This should do it:
SELECT COUNT(ProjectName) AS numCount, ProjectName FROM (
SELECT ProjectName FROM Foo
GROUP BY ProjectName, ReturnCode
) AS Inside
GROUP BY Inside.ProjectName
HAVING numCount = 1
This groups all the ProjectNames by their names and return codes, then selects those that only have a single return code listed.
SQLFiddle Link: http://sqlfiddle.com/#!2/c52b6/11/0
You can try something like this with Not Exists:
Select Distinct ProjectName
From Table A
Where Not Exists
(
Select 1
From Table B
Where B.ProjectName = A.ProjectName
And B.ReturnCode <> A.ReturnCode
)
I'm not sure exactly what you're selecting, so you can change the Select statement to what you need.

Do a while in a query, subquery

I want do query that show data of some users bat, first is a other query, is something difficult of explain. i dont want get the data of the users that me follow, i want see data that me don't follow. So i have two table "follow_follower", "user" and now do a middle query but doesn't match:
follow_follower
cod seguidor seguido
1 1 2
2 1 3
3 1 8
4 1 6
5 8 2
6 2 8
7 2 4
8 3 2
9 5 1
User
cod nombre apellido telefono
1 carlos cardenas 12587
2 Umberto Contreras 125488
3 carlos Torres 44587
4 Victor Sambrano 69754
5 Carlos Barragan 3698741
6 Jorge Cantor
7 Umberto Zanetty 578825
8 Miguel Cantor 5488787
ok and if you see are four fields in follow_follower that the user is 1 (Carlos Cardenas), how do query that first get all user that me follow and after select all data of people diferent "DISTICN" see my query:
select distinct(nombre), apellido, telefono
FROM usuario
where cod<> ANY(select seguido from follow_follower where seguidor=1)
order by cod
But only DISTINC a ANY row of all query.
ok i want a list little of people that me don't follow but i see your query and show error, i know little of mysql query ADVANCE :( and the other problem is that my db is write in spanish... but go to try the table db like are!!! :
this is a the true query:
SELECT distinct(usua.cod), usua.nick, desi.usuario, main.dir, main.size, main.x, main.y, main.R, main.G, main.B, main.A
FROM usuario AS usua, design AS desi, mainPhoto AS main
WHERE desi.usuario = usua.cod
AND desi.cod = main.design
AND usua.cod <> ANY(select seguido from seguidor_seguido where seguidor=1)/**!!!!!/
AND main.dir <> ''
AND main.type =1
ORDER BY usua.nick DESC
LIMIT 44 , 6
so the unique table that true import are usuario (content data of user) and seguidor_seguido(content all the records follow)
---describe table seguidor_seguido:
seguidor_seguido
cod // is the id of the record
seguidor // is the user that follow to other users
seguido // is the user that is followed by other users
Although the request is different from the original is the same problem!!!
thanks :D
Sounds like you want a list of all users that don't follow you. I'm not sure if you want that to be transitive or not (i.e., including users that follow users that follow you, etc.).
If you just want to do it one level deep, it'll go like this. You want to get a list of all entries in the follow_follower where the seguido (I assume that's supposed to mean "person who is being followed") is not you. Users can follow other people, but they can't follow you. You can join twice against the User table to get user names.
SELECT DISTINCT
usuario_seguidor.nombre,
usuario_seguidor.applido,
usuario_seguidor.telephono
FROM follow_follower
JOIN usuario AS usuario_seguidor
ON usuario_seguidor.cod = follow_follower.seguidor
WHERE follow_follower.seguido <> 1
I could finally end the query and match ok!! :D see:
SELECT U.cod, U.nombre, U.apellido, U.telefono FROM User U LEFT JOIN (SELECT f.seguido
FROM follow_follower f
WHERE f.seguidor = 1)t1 ON u.cod = t1.seguido
WHERE t1.seguido IS NULL AND U.cod <> 1 GROUP BY U.cod
this is the query that me need, but i thanks :D