SQL query how do i group by name in a table - sql

SELECT R.CALL,
P.NAME,
R.PID,
TIMESTAMPDIFF( 4, CHAR(TIMESTAMP( M.ENDTIME ) - TIMESTAMP( M.START ))) AS MINUTES
FROM ROSTER R, PLAYER_ON P, MATCH M
WHERE R.CALL = P.CALL
AND R.PID = P.PID
AND M.START = R.START
ORDER BY R.CALL ASC, P.NAME ASC
Above is my query, I successfully get the desired columns from the database.
However I still have one step to go.
The sample output for the query is like:
Output
My question is: how do I sum up the total minutes group by names, for example, Edward Ellis will appear in the output only once with total minutes 573+4933.
Here is my attempt:
SELECT CALL,
NAME,
PID,
SUM(MINUTES)
FROM (
SELECT R.CALL,
P.NAME,
R.PID,
TIMESTAMPDIFF( 4, CHAR(TIMESTAMP( M.ENDTIME ) - TIMESTAMP( M.START ))) AS MINUTES
FROM ROSTER R, PLAYER_ON P, MATCH M
WHERE R.CALL = P.CALL
AND R.PID = P.PID
AND M.START = R.START )
GROUP BY NAME
But there is an error says:
SQL0119N An expression starting with "PID" specified in a SELECT clause,
HAVING clause, or ORDER BY clause is not specified in the GROUP BY clause or
it is in a SELECT clause, HAVING clause, or ORDER BY clause with a column
function and no GROUP BY clause is specified. SQLSTATE=42803
Can someone help with that?

You should learn to use proper join syntax (although that has nothing to do with your error). Simple rule: Never use commas in the from clause. Always use explicit join syntax.
Your problem is due to extraneous columns in the select that are not in the group by. In addition, you don't need the subquery:
SELECT P.NAME, SUM(TIMESTAMPDIFF(4,CHAR(TIMESTAMP(M.ENDTIME)-TIMESTAMP(M.START)))) AS MINUTES
FROM ROSTER R JOIN
PLAYER_ON P
ON R.CALL = P.CALL AND R.PID = P.PID JOIN
MATCH M
ON M.START = R.START
GROUP BY NAME

You have some errors in your query. First, try to use JOIN instead of FROM and WHERE to connect tables. Second, you need to use Having clause to sum up the total minutes.
SELECT r.CALL, p.NAME, r.PID, SUM (TIMESTAMPDIFF(4,CHAR(TIMESTAMP(m.ENDTIME)- TIMESTAMP(m.START)))) AS MINUTES
FROM ROSTER r INNER JOIN PLAYER_ON p ON r.call = p.call AND r.pid=p.pid INNER JOIN INNER JOIN MATCH m ON m.START = r.START
GROUP BY p.NAME
HAVING TIMESTAMPDIFF(4,CHAR(TIMESTAMP(m.ENDTIME)- TIMESTAMP(m.START)))
ORDER BY r.CALL ASC, p.NAME ASC;

Related

Get max/min value of the column independet from where clause

I am having the following query and running it on postgress
select
p.id as p_id,
p.name as p_name,
p.tags,
p.creator,
p.value
p.creation_date,
cp.id as c_part_id,
fr.distance
count(*) OVER() AS total_item
from t_p p
left join t_c_part cp on p.id = cp.p_id
left join t_fl fr on p.id = fr.p_id
where p.name = 'test'
ORDER BY p.id ASC, p.name ASC
OFFSET 0 FETCH NEXT 25 ROWS only
What is missing here is that I also need to get max(p.value) and min(p.value) not affected by the "where" clause - so calculated from total (all) values.
I am dreaming that I can do it within one query and reduce the number of transactions.
Honestly not sure if it is possible!
What I tried is something like this ->
SELECT
(SELECT COUNT(*) from t_p) as count,
(SELECT json_agg(t.*) FROM (
SELECT * FROM t_p
where ***
) AS t) AS rows
But this one did not look really nice as it require additional JSON manipulation at the backend.
I discovered that I might try to use the "with" statement to create a temporary view so the where condition is only evaluated once, but did not succeed to make it works...
You can add the extra columns as scalar subqueries in the form (select min(value) from t_p). Their values are not related to the main query so they should be totally independent.
Your original query has some minor syntax issues (missing commas). I fixed those and the result is:
select
p.id as p_id,
p.name as p_name,
p.tags,
p.creator,
p.value,
p.creation_date,
cp.p_id as c_part_id,
fr.distance,
count(*) OVER() AS total_item,
(select min(value) from t_p) as min_value,
(select max(value) from t_p) as max_value
from t_p p
left join t_c_part cp on p.id = cp.p_id
left join t_fl fr on p.id = fr.p_id
where p.name = 'test'
ORDER BY p.id ASC, p.name ASC
OFFSET 0 FETCH NEXT 25 ROWS only
See running query (without any data) at DB Fiddle.
You can join to a sub-query that calculates both MIN & MAX.
...
from t_p p
left join t_c_part cp on p.id = cp.p_id
left join t_fl fr on p.id = fr.p_id
cross join (
select
min(value) as min_value
, max(value) as max_value
, avg(value) as avg_value
from t_p
) as v
...
Then use v.min_value and v.max_value in the select.
Doesn't even have to be a LATERAL.
You could get the minimum and maximum "on the side" like this:
select
p.id as p_id,
p.name as p_name,
p.tags,
p.creator,
p.value
p.creation_date,
cp.id as c_part_id,
fr.distance,
count(*) OVER() AS total_item,
p.min_value,
p.max_value
from (SELECT id,
name,
tags,
creator,
value,
creation_date,
min(value) OVER () AS min_value,
max(value) OVER () AS max_value,
FROM t_p) AS p
left join t_c_part cp on p.id = cp.p_id
left join t_fl fr on p.id = fr.p_id
where p.name = 'test'
ORDER BY p.id ASC, p.name ASC
OFFSET 0 FETCH NEXT 25 ROWS only;

Display Value from Sub Query in SELECT

I need to display the value MIN(pa.DataAdjudicacao) in the SELECT.
And how can I replace this Subquery for a Join?
How can I do it?
As far as I have searched I haven't found any way to do it.
Please help.
SELECT p.id, p.referencia
FROM PCTSproposta p
WHERE p.ID in (SELECT pa.Proposta
FROM PropostaAdjudicada pa
WHERE pa.Proposta = p.ID
GROUP BY pa.Proposta
HAVING MIN(pa.DataAdjudicacao) >= '2020-10-01' And MIN(pa.DataAdjudicacao) <= '2020-10-31')
Your query is overcomplicated.
You use subquery to filter the data by IN predicate, but select the same ID that you've passed into filter of subquery. So your IN looks like EXISTS.
But if you need that min, you should use JOIN:
SELECT p.id,
p.referencia,
pa2.DataAdjudicacao
FROM PCTSproposta p
JOIN (
SELECT pa.Proposta,
MIN(pa.DataAdjudicacao) as DataAdjudicacao
FROM PropostaAdjudicada pa
GROUP BY pa.Proposta
HAVING MIN(pa.DataAdjudicacao) BETWEEN date '2020-10-01'AND date '2020-10-31'
) pa2
on pa2.Proposta = p.ID
Depending on roles of the Id column (if it is primary key of PCTSproposta), data integrity and cardinality the subquery can be merged into main query:
SELECT p.id,
p.referencia,
MIN(pa.DataAdjudicacao) as DataAdjudicacao
FROM PCTSproposta p
JOIN PropostaAdjudicada pa
on pa2.Proposta = p.ID
GROUP BY p.id,
p.referencia
HAVING MIN(pa.DataAdjudicacao) BETWEEN date '2020-10-01'AND date '2020-10-31'
A lateral join comes to mind:
SELECT p.id, p.referencia, pa.*
FROM PCTSproposta p
CROSS APPLY (
SELECT MIN(pa.DataAdjudicacao) minDataAdjudicacao
FROM PropostaAdjudicada pa
WHERE pa.Proposta = p.ID
) pa
WHERE pa.minDataAdjudicacao >= '20201001' AND pa.minDataAdjudicacao < '20201101'

Is there a way to distinct multiple columns in sql?

Is there a way to distinct multiple columns? When I tried to do it with p.name it says that there is an error that occurred.
SELECT DISTINCT( V.NAME ),
POH.status,
poh.shipdate,
pod.orderqty,
POD.receivedqty,
POD.rejectedqty,
p.NAME
FROM purchasing.vendor v
INNER JOIN purchasing.productvendor pv
ON v.businessentityid = pv.businessentityid
INNER JOIN production.product p
ON pv.productid = P.productid
INNER JOIN purchasing.purchaseorderdetail POD
ON P.productid = POD.productid
INNER JOIN purchasing.purchaseorderheader POH
ON POD.purchaseorderid = POH.purchaseorderid
ORDER BY v.NAME,
p.NAME;
If you want one row per NAME, then you can use ROW_NUMBER():
with q as (
<your query here with columns renamed so there are no duplicates>
)
select q.*
from (select q.*,
row_number() over (partition by v_name order by v_name) as seqnum
from q
) q
where seqnum = 1;
DISTINCT is not a function, it is an operator and its scope is the entire SELECT clause
(The query formatting is just for emphasizing the point)
SELECT DISTINCT
V.NAME,
POH.status,
poh.shipdate,
pod.orderqty,
POD.receivedqty,
POD.rejectedqty,
p.NAME
FROM purchasing.vendor v
...
That answers the error you get, however, I doubt if this will give you the results you are looking for

Dividing Count from Query of count in SQL

I am trying to essentially divide one count by a number I query from another table in SQL
MOVIECOUNT AS (
SELECT COUNT(MS.MOVID) AS MOVCOUNT, MG.GENRE AS GENREPERCOUNT
FROM MOVIESUCCESS MS
INNER JOIN MOVIES_GENRES MG ON MG.MOVIE_ID = MS.movid
group by MG.GENRE
)
SELECT (MC.MOVCOUNT / COUNT(DG.MOVIE_ID))
FROM MOVIECOUNT MC, DIRECTORS_GENRES DG
WHERE MC.GENREPERCOUNT = DG.GENRE
GROUP BY DG.GENRE
I can't get the latter part to compile (the MOVIECOUNT works--just there for reference). The rest of the schema isn't that important, and I have the rest of the code working.
I'm essentially just trying to get the count I found in moviecount (which is done per genre) and divide that by the count of all movies of the same genre. Ideas? Oracle SQL
You probably need to compute each aggregate separately before joining them:
with mgc as (
select
mg.genre,
count(*) as moviecount
from
moviesuccess ms
inner join
movies_genres mg
on mg.movie_id = ms.movid
group by
mg.genre
), dgc as (
select
dg.genre,
count(*) as directorcount
from
directors_genres dg
group by
dg.genre
) select
mgc.genre,
mgc.moviecount / dgc.directorcount
from
mgc
inner join
dgc
on mgc.genre = dgc.genre;
You can do this with the approach you are taking, you just have to be more careful with the aggregation:
WITH MOVIECOUNT AS (
SELECT COUNT(MS.MOVID) AS MOVCOUNT, MG.GENRE AS GENREPERCOUNT
FROM MOVIESUCCESS MS INNER JOIN
MOVIES_GENRES MG
ON MG.MOVIE_ID = MS.movid
group by MG.GENRE
)
SELECT (MC.MOVCOUNT / COUNT(DG.MOVIE_ID))
FROM MOVIECOUNT MC JOIN
DIRECTORS_GENRES DG
ON MC.GENREPERCOUNT = DG.GENRE
GROUP BY MC.GENRE, MC.MOVCOUNT;

Compare subselect value with value in master select

In MS Access, I have a query where I want to use a column in the outer query as a condition in the inner query:
SELECT P.FirstName, P.LastName, Count(A.attendance_date) AS CountOfattendance_date,
First(A.attendance_date) AS FirstOfattendance_date,
(SELECT COUNT (*)
FROM(SELECT DISTINCT attendance_date
FROM tblEventAttendance AS B
WHERE B.event_id=8
AND B.attendance_date >= FirstOfattendance_date)
) AS total
FROM tblPeople AS P INNER JOIN tblEventAttendance AS A ON P.ID = A.people_id
WHERE A.event_id=8
GROUP BY P.FirstName, P.LastName
;
The key point is FirstOfattendance_date - I want the comparison deep in the subselect to use the value in each iteration of the master select. Obviously this doesn't work, it asks me for the value of FirstOfattendance_date when I try to run it.
I'd like to do this without resorting to VB code... any ideas?
How about:
SELECT
p.FirstName,
p.LastName,
Count(a.attendance_date) AS CountOfattendance_date,
First(a.attendance_date) AS FirstOfattendance_date,
c.total
FROM (
tblPeople AS p
INNER JOIN tblEventAttendance AS a ON
a.people_id = p.ID)
INNER JOIN (SELECT people_id, Count (attendance_date) As total
FROM (
SELECT DISTINCT people_id,attendance_date
FROM tblEventAttendance)
Group By people_id) AS c ON
p.ID = c.people_id
GROUP BY
p.ID, c.total;
Can you change
B.attendance_date >= FirstOfattendance_date
to
B.attendance_date >= First(A.attendance_date)