I have searched for hours for a solution to this mysql user case. I have found many examples but none of them had composite primary keys. I want to do a count across 2 tables and also calculate a difference. Here are the two separate queries
primary key testId, tpId
SELECT Count(*) AS count,
testid,
tpid
FROM cicdexpecteddocument e
WHERE e.testid = 8
GROUP BY e.tpid;
3 8 756abdaa-31c0-11ea-9c52-0245f4ff0412
3 8 7ea2b31b-31c0-11ea-9c52-0245f4ff0412
1 8 c25780cb-31c0-11ea-9c52-0245f4ff0412
2 8 c9f70ed9-31c0-11ea-9c52-0245f4ff0412
primary key testId, tpId, executionId
SELECT Count(*) AS count,
testid,
tpid
FROM cicdactualdocument a
WHERE a.testid = 8
AND a.executionid =
'execution-d0c5e270-50f2-472e-a609-ac2c381e0a5f-2020.01.09'
GROUP BY tpid;
2 8 7ea2b31b-31c0-11ea-9c52-0245f4ff0412
2 8 c25780cb-31c0-11ea-9c52-0245f4ff0412
2 8 c9f70ed9-31c0-11ea-9c52-0245f4ff0412
I would like to end up with something like
3 3 8 756abdaa-31c0-11ea-9c52-0245f4ff0412
3 2 1 8 87ea2b31b-31c0-11ea-9c52-0245f4ff0412
1 2 -1 8 8c25780cb-31c0-11ea-9c52-0245f4ff0412
2 2 0 8 8c9f70ed9-31c0-11ea-9c52-0245f4ff0412
Any guidance is appreciated. Thank you in advance
Here's the code. See below for an explanation.
SELECT count_t1, count_t2,
IFNULL(count_t1, 0) - IFNULL(count_t2, 0) AS diff,
t1.testid, t1.tpid
FROM (
SELECT COUNT(*) AS count_t1,
testid,
tpid
FROM cicdexpecteddocument e
WHERE e.testid = 8
GROUP BY e.tpid
) AS t1
LEFT OUTER JOIN
(
SELECT COUNT(*) AS count_t2,
testid,
tpid
FROM cicdactualdocument a
WHERE a.testid = 8 AND a.executionid =
'execution-d0c5e270-50f2-472e-a609-ac2c381e0a5f-2020.01.09'
GROUP BY tpid
) AS t2 ON t1.testid = t2.testid AND t1.tpid = t2.tpid
ORDER BY tpid
Dissecting this:
Skip past the SELECT columns and notice how the two queries that you specified for each table are contained in parenthesis followed by "AS t1" (or t2) -- those are subqueries. After the 2nd subquery (2nd to last line) is where I specified the join condition.
Next is how the "diff" column is calculated. It uses the IFNULL() function which returns the value specified in the 2nd parameter if the primary value is NULL. That allows the database to do the calculation even on NULL values.
Note: I just put this together quick and dirty, but I'm not making any assumptions about speed here. If you have a couple hundred rows, no big deal. But if you're dealing with thousands of rows in each table, you may need to work on optimizing this query.
Hope that helps!
Related
Borrower_id Branch_id
7 1
8 1
8 2
9 1
9 2
With the table above, I am trying to find a query that gives me the common branch_id for borrower_id values. I do not know the values of branch_id but I know that the numbers 7, 8 and 9 have the value 1 as common values whereas the numbers 8 and 9 have the common value 2 (which I don't want to select because 7 has to be included, again, because of the common value 1).
This is the expected output :
Borrower_id Branch_id
7 1
8 1
9 1
Is there a way I can achieve this? Any suggestion will be appreciated.
How about this? Tested with you current set of data but need to be tested in different scenarios you have.
SELECT a.* FROM your_table a
INNER JOIN
(
SELECT branch_id, COUNT(branch_id) cnt
FROM your_table
GROUP BY branch_id
HAVING cnt = (SELECT COUNT(DISTINCT borrower_id) FROM your_table)
) b ON b.branch_id = a.branch_id
In MySQL 5.5, assume we have the following MAIN table
Id Name Score
3 a 100
3 b 99
4 c 98
4 d 97
Also a SUB table:
Id New_Id
3 1
3 1
4 2
4 2
The ideal output is OUTPUT table:
Id Name Score
3 a 100
3 b 99
4 c 98
4 d 97
1 a 100
1 b 99
2 c 98
2 d 97
The MySQL fiddle is available here
http://sqlfiddle.com/#!9/91c1cf/6
In the OUTPUT table,
we can see that the Id=1 shares the same information as Id =3. Similarly,
we can see that the Id=2 shares the same information as Id =4.
Is there any simple way such as "INSERT INTO...SELECT", "COPY", and "UPDATE" etc. that we can just copy the data from Id=3 to Id=1, and
copy the data from Id=4 to Id=2?
The following query does generate our ideal output, but the JOIN with the proper indexes is still painfully slow in our few hundreds millions rows. The job even fails due to not sufficient RAM and /tmp folder space in the case of few billion rows. We are upgrading our system from MySQL to somewhere more scab-able. However, we need to make sure the MySQL system will be functional during the few months of the transit period. Any 2 cents will be highly appreciated!
SELECT Id, Name, Score FROM MAIN
UNION
SELECT d.New_Id AS Id, c.Name, c.Score FROM MAIN c
RIGHT JOIN SUB d
ON c.Id = d.Id;
Use INNER JOIN rather than RIGHT JOIN, since you don't need the null rows that result from non-matching rows. You can use INSERT INTO ... SELECT to add these new rows to the table. And rather than using UNION, you can simply do two inserts into the new table:
INSERT INTO OUTPUT (id, name, score)
SELECT id, name, score
FROM MAIN;
INSERT INTO OUTPUT (id, name, score)
SELECT d.new_id, c.name, c.score
FROM MAIN AS c
JOIN SUB AS d ON c.id = d.id;
As long as you have indexes on the id columns in both input tables this should be as efficient as possible.
Finally, when doing large UNION queries, use UNION ALL if you know there are no duplicates that need to be merged. UNION by itself defaults to UNION DISTINCT, so it needs to create a temporary table to hold all the results to scan for duplicates.
I have a table with columns similar to below , but with about 30 date columns and 500+ records
id | forcast_date | actual_date
1 10/01/2013 12/01/2013
2 03/01/2013 06/01/2013
3 05/01/2013 05/01/2013
4 10/01/2013 09/01/2013
and what I need to do is get a query with output similar to
week_no | count_forcast | count_actual
1 4 6
2 5 7
3 2 1
etc
My query is
SELECT weekofyear(forcast_date) as week_num,
COUNT(forcast_date) AS count_forcast ,
COUNT(actual_date) AS count_actual
FROM
table
GROUP BY
week_num
but what I am getting is the forcast_date counts repeated in each column, i.e.
week_no | count_forcast | count_actual
1 4 4
2 5 5
3 2 2
Can any one please tell me the best way to formulate the query to get what I need??
Thanks
try:
SELECT weekofyear(forcast_date) AS week_forcast,
COUNT(forcast_date) AS count_forcast, t2.count_actual
FROM
t t1 LEFT JOIN (
SELECT weekofyear(actual_date) AS week_actual,
COUNT(forcast_date) AS count_actual
FROM t
GROUP BY weekOfYear(actual_date)
) AS t2 ON weekofyear(forcast_date)=week_actual
GROUP BY
weekofyear(forcast_date), t2.count_actual
sqlFiddle
You have to write about 30 (your date columns) left join, and the requirement is that your first date column shouldn'd have empty week (with a count of 0) or the joins will miss.
Try:
SELECT WeekInYear, ForecastCount, ActualCount
FROM ( SELECT A.WeekInYear, A.ForecastCount, B.ActualCount FROM (
SELECT weekofyear(forecast_date) as WeekInYear,
COUNT(forecast_date) as ForecastCount, 0 as ActualCount
FROM TableWeeks
GROUP BY weekofyear(forecast_date)
) A
INNER JOIN
( SELECT * FROM
(
SELECT weekofyear(forecast_date) as WeekInYear,
0 as ForecastCount, COUNT(actual_date) as ActualCount
FROM TableWeeks
GROUP BY weekofyear(actual_date)
) ActualTable ) B
ON A.WeekInYear = B.WeekInYear)
AllTable
GROUP BY WeekInYear;
Here's my Fiddle Demo
Just in case someone else comes along with the same question:
Instead of trying to use some amazing query, I ended up creating an array of date_columns_names and a loop in the program that was calling this query, and for each date_column_name, performing teh asme query. It is a bit slower, but it does work
I need a little help with a MySQL query.
I have two tables one table is a list of backlinks with a is_homepage (bool) flag. The second table is a list of the domains for all of the backlinks, a was link_found (bool) flag, and a url_count column which is the number of rows in the backlinks table that are associated with each domain.
Note that the domain_id column is the foreign key to the domain table id column. Heres some sample data.
backlinks
id domain_id is_homepage page_href
1 1 1 http://ablog.wordpress.com/
2 1 0 http://ablog.wordpress.com/contact/
3 1 0 http://ablog.wordpress.com/archives/
4 2 1 http://www.somewhere.org/
5 2 0 http://www.somewhere.org/page=3
6 3 1 http://www.great-fun-site.com/
7 3 0 http://www.great-fun-site.com/index.html
8 4 0 http://red.blgspot.com/page=7
9 4 0 http://blue.blgspot.com/page=9
domains
id url_count link_found domain_name
1 3 1 wordpress.com
2 2 0 somewhere.org
3 2 1 great-fun-site.com
4 2 1 blgspot.com
The results Im looking to get from the above data would be: count = 2, total = 5.
Im trying to get the count of rows from the domains table (count) and then the sum of the url_count (total) from the domains table WHERE link_found is 1 and where one of the links in the backlink table is_homepage is 1.
Here's the query I'm trying to work with.
SELECT SUM(1) AS count, SUM(`url_count`) total
FROM `domains` AS domain
LEFT JOIN `backlinks` AS link ON link.domain_id = domain.id
WHERE domain.id IN (
SELECT DISTINCT(bl.domain_id)
FROM `backlinks` AS bl
WHERE bl.tablekey_id = 11
AND bl.is_homepage = 1
)
AND domain.link_found = 1
AND link.is_homepage = 1
GROUP BY `domain`.`id`
The problem with this query is that it returns a row for each entry in the domains table. I think I might need one more sub query to add up the returned results but I'm not sure if that's correct. Does anyone see what I'm doing wrong? Thank you!
EDIT:
The problem I'm having is that if there are more than one homepage in the back-links table then its counted multiple times. I need to only count each domain once.
Well, you shouldn't have to do a group by as you are not selecting anything other than aggregated fields. I'm no mysql expert, but this should work:
SELECT count(d.id) as count, sum(d.url_count) as total from domains as d
inner join backlinks as b
on b.domain_id = d.id
Where d.Link_found = 1 and b. is_homepage = 1
The reason you're getting a row for each entry in the domains table is that you're grouping by domain.id. If you want grand totals only, just leave off the GROUP BY piece.
I think a fairly simple query will do the trick:
SELECT COUNT(*), SUM(domains.URL_Count)
FROM domains
WHERE domains.link_found = 1 AND domains.id IN (
SELECT domain_id FROM backlinks WHERE is_homepage = 1)
There's a working SQLFiddle here.
Thanks for the help. Sorry it was so hard to explain I need a MySQL fiddle :)
If anyones interested heres what I ened up with:
SELECT SUM(1) AS count, SUM(total) AS total
FROM
(
SELECT SUM(`url_count`) total
FROM `domains` AS domain
LEFT JOIN `backlinks` AS link ON link.domain_id = domain.id
WHERE domain.id IN (
SELECT DISTINCT(bl.domain_id)
FROM `backlinks` AS bl
WHERE bl.tablekey_id = 11
AND bl.is_homepage = 1
)
AND domain.link_found = 1
AND link.is_homepage = 1
GROUP BY `domain`.`id`
) AS result
I get a list of options with price like the following:
(it's the result from a select query sort by price asc)
price color quanlity
o_id
1 2 R medium
3 3 G bad
4 4 G good
5 6 B good
2 8 R medium
Now I need to pair those options according to requirements:
e.g. if I need 2 R(red) and 4 G(green)
I'd like to return a list of possible combinations (sort by price asc), like:
R(2) G(4)
c_id o_id o_id total price
1 1 3 16
2 1 4 20
3 2 3 28
4 2 4 32
My current solution for this is to make multiple queries to the DB:
(I'm using Java at the application layer / back end.)
select distinct colors, and store it in a List
In a For loop, select options of each color into a different temp table
join the List of Tables, and calculate the total, sort by total.
But is there a way to condense the above operations into a stored procedure or something more elegant?
You just need a simple self-join:
SELECT R.o_id AS R_id, G.o_id AS G_id, 2*R.price + 4*G.price AS total
FROM mytable R JOIN mytable G ON R.color = 'R' AND G.color = 'G'
ORDER BY total
See it on sqlfiddle.