How to do this query against MySQL database table? - mysql

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.

Related

Combine one table with meta data in another table

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

MySQL - SELECT to return ids from same table in a subselect

The issue to be addressed is the following:
All ids where matrix_id are the same and relationship task with stage_id = 1 is complete = true and current_phase = 5
And All ids where deviation_id are the same and the task with stage_id = 1 and complete = true and current_phase = 5
All ids where stage = 2 and current_phase is [2,3 or 4] and complete = false (Sorted)
Once they return the data correct, i need to make them a single query, so it would return all the ids for all three queries
Sample data and queries https://www.db-fiddle.com/f/iWC2SrAmV8nKZNR9dqU5Qm/3
I would say Kirs Kringle had a very good solution there, but still missing few things.
First query is returning two items, the second (ID #4) with stage_id = 1 is completed but not is not in the current_phase = 5, so it should not be returned
Same happening with the second query, where the second item should not be returned because its relationship task in stage 1 is not in the current_phase = 5
Third query is ok already.
It needs to be a single query with all 3 queries together.
The question is very difficult to understand. I did the best I could with the info you provided.
I used the following to create the table in the second shown example (by no means should you use this for your real table schema. I put this together quickly):
CREATE DATABASE IF NOT EXISTS TEST;
CREATE TABLE IF NOT EXISTS TEST.test_table (
ID INT AUTO_INCREMENT PRIMARY KEY,
SYSTEM_ID INT(10) NOT NULL,
TYPE_ID INT(10) NOT NULL,
STAGE_ID INT(10) NOT NULL,
CURRENT_PHASE INT(10) NOT NULL,
COMPLETE BOOLEAN,
MATRIX_ID INT(10),
DEVIATION_ID INT
);
INSERT INTO TEST.test_table (ID,SYSTEM_ID,TYPE_ID,STAGE_ID,CURRENT_PHASE,COMPLETE,MATRIX_ID,DEVIATION_ID)
VALUES
(NULL,1,1,1,5,true,1,NULL),
(NULL,1,1,2,1,false,1,NULL),
(NULL,1,2,1,4,false,2,NULL),
(NULL,1,2,2,1,false,2,NULL),
(NULL,1,2,1,5,true,NULL,1),
(NULL,1,2,2,1,false,NULL,1);
I then created the following queries to answer your questions 1,2, and 3. I'm not sure if you wanted them all answered with one query I do not think anything in the set of data you provided would meet that criteria I decided to not entertain it.
1 - All ids where matrix_id are the same and the task with stage_id = 1 is complete = true:
SELECT
MAX(ID) ID
FROM TEST.test_table tt
WHERE MATRIX_ID IS NOT NULL
GROUP BY tt.MATRIX_ID
HAVING SUM(tt.COMPLETE) = (COUNT(*)-1)
;
Answer is: ID 2
Note: I guess this wouldn't be considered checking if STAGE_ID is 1 and true, but I think it effective gets you the same result and as time goes on it will always make sure that the task before it was completed as the SUM of the completed boolean field should always be 1 less than the total number of tasks BUT stay you start stacking more tasks you will need to refine this a bit and come up with something a bit more exact.
2 - And All ids where deviation_id are the same and the task with stage_id = 1 and complete = true:
SELECT
MAX(ID) ID
FROM TEST.test_table tt
WHERE tt.DEVIATION_ID IS NOT NULL
GROUP BY tt.DEVIATION_ID
HAVING SUM(tt.COMPLETE) = (COUNT(*)-1)
;
Answer is: ID 6
3 - All ids where stage = 2 and current_phase is [2,3 or 4] and complete = fal:
SELECT
tt.ID
FROM TEST.test_table tt
WHERE tt.STAGE_ID = 1
AND tt.CURRENT_PHASE IN (2,3,4)
AND tt.COMPLETE = false
;
Answer is: ID 3
I think that by understanding the GROUP BY command and the HAVING command you will gain some insight into how you might solve these problems.
You can test this out here: https://www.db-fiddle.com/f/dD67jzQpENdJ5YSLBxoLbD/0

How to insert SUM() function that sums rows with similar ID in a code part of witch is unchangeable?

I am trying to write a quarry in a module for Dolibarr ERP. But module hase a part of code that is predefined and can not be changed. And I need to insert a SUM() function in it that will combine rows with similar id. That i know how to do in a regular MySQL:
SELECT fk_product AS prod, SUM(value) AS qty
FROM llx_stock_mouvement
WHERE type_mouvement = 2 AND label LIKE 'SH%'
GROUP BY fk_product
ORDER BY 1 DESC
LIMIT 26
that gives me what I want :
prod qty
1 13
2 10
BUT module has a predefined unchangeable code :
this part is predefined module writes it himself based on values provider in it:
SELECT DISTINCT
c.fk_product AS com,
c.value AS qty
THIS PART I CAN WRITE IN A MODULES GUI:
FROM
llx_stock_mouvement AS c
WHERE
type_mouvement = 2
AND label LIKE 'SH%'
And this part is predefined:
ORDER BY 1 DESC
LIMIT 26
I would appreciate any help and advice on question is there any workaround that can be done to make my desired and result ampere ? As it would using the first code I posted ?
If you can only modify the bit in the middle box then you might need to use a subquery;
--fixed part
SELECT DISTINCT
c.fk_product AS com,
c.value AS qty
--begin your editable part
FROM
(
SELECT fk_product,
SUM(value) AS value
FROM llx_stock_mouvement
WHERE type_mouvement = 2 AND label LIKE 'SH%'
GROUP BY fk_product
) c
--end your editable part
--fixed part
ORDER BY 1
DESC
LIMIT 26

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

Retrieve maximum value from a table containing duplicate values according to a condition

I have a table tbl_usertests from which i want to retrieve the user who have maximum testscore for each test.
Note: User here means usertestid which is unique.
Its colums are:
pk_usertestid attemptdate uploaddate fk_tbl_tests_testid fk_tbl_users_userid testscore totalquestionsnotattempted totalquestionscorrect totalquestionsincorrect totalquestions timetaken iscurrent
data :
1;NULL;"2010-06-24 22:48:07";"11";"3";"1";"53";"1";"21";"75";"92";"1"
2;NULL;"2010-06-25 01:21:37";"11";"4";"13";"0";"13";"62";"75";"801";"1"
3;NULL;"2010-06-25 01:21:50";"10";"4";"17";"5";"17";"53";"75";"640";"1"
4;NULL;"2010-06-25 01:24:23";"11";"4";"13";"0";"13";"62";"75";"801";"1"
5;NULL;"2010-06-25 01:24:47";"10";"4";"17";"5";"17";"53";"75";"640";"1"
6;NULL;"2010-06-25 01:36:04";"11";"5";"13";"0";"13";"62";"75";"801";"1"
7;NULL;"2010-06-25 01:47:26";"7";"5";"10";"1";"10";"49";"60";"302";"1"
My Query is :
SELECT max(`testscore`) , `fk_tbl_tests_testid` , `fk_tbl_users_userid` , `pk_usertestid`
FROM `tbl_usertests`
GROUP BY `fk_tbl_tests_testid`
This query output:
max(`testscore`) fk_tbl_tests_testid fk_tbl_users_userid pk_usertestid
10 7 5 7
17 10 4 3
13 11 3 1
But the problem is that if there are two users who have same score, it displays only one user because i have used group by clause.
For. e.g. testid =10 i have two records(pk_usertestid 3 and 5) but it displays 3 only.
I want the user whose upload date is less than the other user(in case of two users having same testscore). It should display for usertestid=3 since 3 upload date is less than 5.
Right now its displaying 3 but it is due to group by clause.
I am unable to construct the query.
Please help me on this
Thanks
Try this:
SELECT t.`fk_tbl_tests_testid` , t.`fk_tbl_users_userid` , t.`pk_usertestid`, maxscores.maxscore
FROM `tbl_usertests` t
JOIN (SELECT `fk_tbl_tests_testid`,max(`testscore`) as maxscore
FROM `tbl_usertests`
GROUP BY `fk_tbl_tests_testid`) maxscores ON t.`fk_tbl_tests_testid` = maxscores.`fk_tbl_tests_testid`
the logic behind is to separate the whole thing into two parts: get the maximum (or any other aggregate) values for each group (this is the subquery part), then for each element, join the corresponding aggregate. (JOIN it back to the riginal table)