How can I join SQL subqueries as they are? - mysql

I have 3 subqueries that when executed independently they all return 3 rows with the desired columns and values. Once I put them all in the from statement and select them all
SELECT
*,
ROUND(Verbrecher / Buerger * 100, 1) AS Sicherheitsgrad
FROM
(SELECT name AS Dorf
FROM dorf
GROUP BY dorfnr) AS Dorf,
(SELECT COUNT(*) AS Verbrecher
FROM bewohner
WHERE status LIKE 'boese'
GROUP BY dorfnr) AS Verbrecher,
(SELECT COUNT(*) AS Buerger
FROM bewohner
GROUP BY dorfnr) AS Buerger
This is the result of all three subqueries being respectively executed standalone
Standalone
This is the result
Snippet above being run
I expect them to be joined together and have three rows with the queries aligned horizontally.
That unfortunately is not the given result.
I hope this makes sense to a certain extent.

Maybe you need in this:
SELECT dorfnr, Dorf, Verbrecher, Buerger,
ROUND(Verbrecher / Buerger * 100, 1) AS Sicherheitsgrad
FROM ( SELECT dorfnr, name AS Dorf
FROM dorf
-- GROUP BY dorfnr
) AS Dorf
JOIN ( SELECT dorfnr, COUNT(*) AS Verbrecher
FROM bewohner
WHERE status LIKE 'boese'
GROUP BY dorfnr
) AS Verbrecher USING (dorfnr)
JOIN ( SELECT dorfnr, COUNT(*) AS Buerger
FROM bewohner
GROUP BY dorfnr
) AS Buerger USING (dorfnr)

Related

Using the results of a function multiple times for duplicates - SQL

I am trying to produce a result that shows duplicates in a table. One method I found for getting duplicates and showing them is to run the select statement again through an inner join. However, one of my columns needs to be the result of a function, and the only thing I can think to do is use an alias, however I can't use the alias twice in a SELECT statement.
I am not sure what the best way to run this code for getting the duplicates I need.
My code below
SELECT EXTRACT(YEAR_MONTH FROM date) as 'ndate', a.transponderID
FROM dispondo_prod_disposition.event a
inner JOIN (SELECT EXTRACT(YEAR_MONTH FROM date) as ???,
transponderID, COUNT(*)
FROM dispondo_prod_disposition.event
GROUP BY mdate, transponderID
HAVING count(*) > 1 ) b
ON ndate = ???
AND a.transponderID = b.transponderID
ORDER BY b.transponderID
SELECT b.ndate, transponderID
FROM dispondo_prod_disposition.event a
INNER JOIN ( SELECT EXTRACT(YEAR_MONTH FROM date) as ndate,
transponderID
FROM dispondo_prod_disposition.event
GROUP BY 1, 2
HAVING COUNT(*) > 1 ) b USING (transponderID)
WHERE b.ndate = ??? -- for example, WHERE b.ndate = 202201
ORDER BY transponderID

mysql select statement for multiple table

This is just a test project. I want to know how to select All professors with more than 5 failed students in a subject
I already know how to select All professors with at least 2 subjects with the following query:
SELECT paulin_professors.*,
IFNULL(sub_p.total, 0) num
FROM paulin_professors
LEFT JOIN ( SELECT COUNT(*) total, pau_profid
FROM paulin_profsubject
GROUP BY pau_profid
) sub_p ON (sub_p.pau_profid = paulin_professors.pau_profid)
WHERE sub_p.total >= 2;
I know I'm close but I can't get it to work (All professors with more than 5 failed students in a subject) . Any ideas? TIA
try using SELECT with UNION
select [columnName1],[columnName2] from [Table1] where [condition] union select [columnName1],[columnName2] from [Table1] where [condition] union ....
Looks like can get the professor IDs from the profsubject table and JOIN the studentenrolled table using the subjid for the join. In a similar way to what you had, you can get the count of students who have a grade less than a certain pass/fail threshold (in this case 65).
Then to get a short list, you can select the distinct profids from this derivaed table.
SELECT
distinct pau_profid
FROM
(SELECT
t1.pau_profid,
IFNULL(t2.total_failed, 0) number_failed >= 5
FROM
paulin_profsubject t1
LEFT JOIN
(SELECT
COUNT(*) total_failed,
pau_subjid
FROM
paulin_studentenrolled
WHERE
pau_grade < 65
GROUP BY
pau_subjid
) t2
ON
t1.pau_subjid = t2.pau_subjid
WHERE
number_failed >= 5
) t3;

How do I make an SQL Query to find the max of an aggregate function like "count"?

This is the query I need in English:
Display the animal id, name, and number of exams of the animal(s) with the most examinations done on them.
Consider there might be ties for first place. In that case all tied animals should be returned.
Here's some relevant SQL:
select an_id, an_name, count(distinct ex_id) as NumberExams
from vt_animals
join vt_exam_headers using (an_id)
How can I do this without using desc and limit and ideally with group by? I thought of using max, but it doesn't seem to work with count.
If I understand well the query, something like this would return the group of animals if more than one have the most number of examinations:
SELECT a.an_id, a.an_name, a.number_exams
FROM (SELECT an_id, an_name, COUNT(ex_id) as number_exams
FROM vt_animals
JOIN vt_exam_headers USING (an_id)
GROUP BY an_id) AS a
HAVING a.number_exams >= MAX(a.number_exams)
You have to use group by clause to the column names which are not in the aggregate functions
select an_id, an_name, count(distinct ex_id) as NumberExams
from vt_animals
group by an_id, an_name
First select animal with most examinations:
SELECT an_id,count(ex_id) FROM animals GROUP BY an_id ORDER BY count(*) DESC LIMIT 1
Then you can use it as a subquery.
Explanation: you sort this table descending by count(*) and then you choose top 1, which is maximum.
Depending on the database product you're using, this could vary in complexity. For example, emibloque's answer will not work in MS SQL Server because the having clause needs to correspond with the group by clause. In this case, you'd have to do something along these lines:
select * from
(
select an_name, count(*) exams
from vt_animals a join vt_exam_headers e on a.an_id = e.an_id
group by an_name
) sub1
where exams =
(
select max(exams) from
(
select an_id, count(*) exams
from vt_exam_headers
group by an_id
) sub2
)
or if you prefer the use of variables:
declare #max_exams int;
select #max_exams = (
select max(exams) from
(
select an_id, count(*) exams
from vt_exam_headers
group by an_id
) sub
);
select * from
(
select an_name, count(*) exams
from vt_animals a join vt_exam_headers e on a.an_id = e.an_id
group by an_name
) sub1
where exams = #max_exams

Inner join to select MAX value from the SUM of Rows

http://sqlfiddle.com/#!2/1a2df
I am trying to select a column "photo_name" by counting the MAX value of SUM(valid)
the preferred results is "test5.jpg" but after hours of trying, I still can't figure it out ,
below is my previous approach, but it doesn't work
SELECT photo_name FROM
(
SELECT a.*
FROM test a
INNER JOIN
(
SELECT *, SUM(valid) v
FROM test
WHERE page_id = 3 AND `valid` = 1
) b ON MAX(b.v)
)c
Please help,
Something like this should work. It sums the valid column for each photo, orders high-to-low for the sum, then limits results to the top row:
SELECT photo_name, SUM(valid) AS sum_valid
FROM test
GROUP BY photo_name
ORDER BY sum_valid DESC
LIMIT 1

How to use actual row count (COUNT(*)) in WHERE clause without writing the same query as subquery?

I have something like this:
SELECT id, fruit, pip
FROM plant
WHERE COUNT(*) = 2;
This weird query is self explanatory I guess. COUNT(*) here means the number of rows in plant table. My requirement is that I need to retrieve values from specified fields only if total number of rows in table = 2. This doesn't work but: invalid use of aggregate function COUNT.
I cannot do this:
SELECT COUNT(*) as cnt, id, fruit, pip
FROM plant
WHERE cnt = 2;
for one, it limits the number of rows outputted to 1, and two, it gives the same error: invalid use of aggregate function.
What I can do is instead:
SELECT id, fruit, pip
FROM plant
WHERE (
SELECT COUNT(*)
FROM plant
) = 2;
But then that subquery is the main query re-run. I'm presenting here a small example of the larger part of the problem, though I know an additional COUNT(*) subquery in the given example isn't that big an overhead.
Edit: I do not know why the question is downvoted. The COUNT(*) I'm trying to get is from a view (a temporary table) in the query which is a large query with 5 to 6 joins and additional where clauses. To re-run the query as a subquery to get the count is inefficient, and I can see the bottleneck as well.
Here is the actual query:
SELECT U.UserName, E.Title, AE.Mode, AE.AttemptNo,
IF(AE.Completed = 1, 'Completed', 'Incomplete'),
(
SELECT COUNT(DISTINCT(FK_QId))
FROM attempt_question AS AQ
WHERE FK_ExcAttemptId = #excAttemptId
) AS Inst_Count,
(
SELECT COUNT(DISTINCT(AQ.FK_QId))
FROM attempt_question AS AQ
JOIN `question` AS Q
ON Q.PK_Id = AQ.FK_QId
LEFT JOIN actions AS A
ON A.FK_QId = AQ.FK_QId
WHERE AQ.FK_ExcAttemptId = #excAttemptId
AND (
Q.Type = #descQtn
OR Q.Type = #actQtn
AND A.type = 'CTVI.NotImplemented'
AND A.IsDelete = #status
AND (
SELECT COUNT(*)
FROM actions
WHERE FK_QId = A.FK_QId
AND type != 'CTVI.NotImplemented'
AND IsDelete = #status
) = 0
)
) AS NotEvalInst_Count,
(
SELECT COUNT(DISTINCT(FK_QId))
FROM attempt_question AS AQ
WHERE FK_ExcAttemptId = #excAttemptId
AND Mark = #mark
) AS CorrectAns_Count,
E.AllottedTime, AE.TimeTaken
FROM attempt_exercise AS AE
JOIN ctvi_exercise_tblexercise AS E
ON AE.FK_EId = E.PK_EId
JOIN ctvi_user_table AS U
ON AE.FK_UId = U.PK_Id
JOIN ctvi_grade AS G
ON AE.FK_GId = G.PK_GId
WHERE AE.PK_Id = #excAttemptId
-- AND COUNT(AE.*) = #number --the portion in contention.
Kindly ignore the above query and guide me to right direction from the small example query I posted, thanks.
In MySQL, you can only do what you tried:
SELECT id, fruit, pip
FROM plant
WHERE (
SELECT COUNT(*)
FROM plant
) = 2;
or this variation:
SELECT id, fruit, pip
FROM plant
JOIN
(
SELECT COUNT(*) AS cnt
FROM plant
) AS c
ON c.cnt = 2;
Whether the 1st or the 2nd is more efficient, depends on the version of MySQL (and the optimizer). I would bet on the 2nd one, on most versions.
In other DBMSs, that have window functions, you can also do the first query that #Andomar suggests.
Here is a suggestion to avoid the bottleneck of calculating the derived table twice, once to get the rows and once more to get the count. If the derived table is expensive to be calculated, and its rows are thousands or millions, calculating them twice only to throw them away, is a problem, indeed. This may improve efficiency as it will limit the intermediately (twice) calculated rows to 3:
SELECT p.*
FROM
( SELECT id, fruit, pip
FROM plant
LIMIT 3
) AS p
JOIN
( SELECT COUNT(*) AS cnt
FROM
( SELECT 1
FROM plant
LIMIT 3
) AS tmp
) AS c
ON c.cnt = 2 ;
After re-reading your question, you're trying to return rows only if there are 2 rows in the entire table. In that case I think your own example query is already the best.
On another DBMS, you could use a Windowing function:
select *
from (
select *
, count(*) over () as cnt
from plant
) as SubQueryAlias
where cnt = 2
But the over clause is not supported on MySQL.
old wrong anser below
The where clause works before grouping. It works on single rows, not groups of rows, so you can't use aggregates like count or max in the where clause.
To set filters that work on groups of rows, use the having clause. It works after grouping and can be used to filter with aggregates:
SELECT id, fruit, pip
FROM plant
GROUP BY
id, fruit, pip
HAVING COUNT(*) = 2;
The other answers do not fulfill the original question which was to filter the results "without using a subquery".
You can actually do this by using a variable in 2 consecutive MySQL statements:
SET #count=0;
SELECT * FROM
(
SELECT id, fruit, pip, #count:=#count+1 AS count
FROM plant
WHERE
) tmp
WHERE #count = 2;