SQL Select rows with value that appears x times - sql

SELECT Opponent, JerseyNumber, A
FROM (SELECT * FROM Games_t INNER JOIN GameStats_t ON Games_t.GameID=GameStats_t.GameID)
WHERE A >=1 AND COUNT(Opponent) >3;
I'm trying to return games where there were at least three players who recorded one assist or more. If I don't have AND COUNT(Opponent) >3, the query returns almost what I want, but there are a few games where only three players recorded an assist.

Try this :
SELECT Opponent,
JerseyNumber,
A,
COUNT(Opponent) FROM
(
SELECT *
FROM Games_t INNER JOIN GameStats_t
ON Games_t.GameID=GameStats_t.GameID
)
WHERE A >=1
GROUP BY Opponent, JerseyNumber, A
HAVING COUNT(Opponent) >3

Use the following Query.
SELECT G_TEMP.GAME_ID, GT.OPPONENT, GT.JERSEYNUMBER, G.A FROM
(
SELECT GAME_ID, COUNT(OPPONENT) OPP_COUNT FROM GAMESTATS_T
HAVING COUNT(OPPONENT) > 3
GROUP BY GAME_ID
) G_TEMP
LEFT OUTER JOIN
GAMES_T G
ON
G.GAME_ID = G_TEMP.GAME_ID
AND G.A > 1
INNER JOIN
GAMESTATS_T GT
ON
G.GAME_ID = GT.GAME_ID
Working SQL Fiddle HERE
Note 1: When there are more than one table, it is always better to specify fields using tablename_alias.field_name syntax. This is a good practice, however it is optional.
For example, if Table TABLEA has fields FIELDA1, FIELDA2, FIELDA3 and if Table TABLEB has fields FIELDB1, FIELDB2
Then you can use query as:
SELECT A.FIELDA1, A.FIELDA3, B.FIELDB2
FROM TABLEA A JOIN TABLEB B ON A.FIELDA2 = B.FIELDB2

Use HAVING part in query to use some parameters after query completion:
SELECT Opponent, JerseyNumber, A
FROM (SELECT * FROM Games_t INNER JOIN GameStats_t ON Games_t.GameID = GameStats_t.GameID)
WHERE A >=1 HAVING COUNT(Opponent) > 3;

Related

SQL Table Joining

I'm joining these three tables, but the same information gets displayed 3 times ... Any idea how to have only the unique rows to be displayed, as determined by unique shipment id's?
SELECT S.SHIPMENT_ID, S.CREATION_DATE, S.BUSINESS_ID, B.BUS_ID, S.SHIPMENT_STATUS, S.BUSINESS_NAME, S.SHIPMENT_MODES, S.CUSTOMER_NAME
FROM "SHIPMENT" S
INNER JOIN "BUSINESS" B ON S.BUSINESS_ID=B.BUS_ID
INNER JOIN "SHIPMENT_GROUP" SG ON S.SHIPMENT_ID=SG.SHIPMENT_ID
INNER JOIN "DATA_GROUP" DG ON DG.ID=SG.GROUP_ID
try select distinct
SELECT DISTINCT column1, column2, ...
FROM table_name;
w3schools
You are selecting rows from the first table only, so this suggests that you are using the joins for filtering.
If so, you can rewrite this with exists, which will avoid duplicates if there are multiple matches. Starting from your existing query, the logic would be:
select s.*
from shipment s
where
exists (
select 1
from business b
where b.bus_id = s.business_id
) and exists (
select 1
from shipment_group sg
inner join data_group dg on dg.id = sg.group_id
where sg.shipment_id = s.shipment_id
)

PostgreSQL GROUP BY column must appear in the GROUP BY

SELECT
COUNT(follow."FK_accountId"),
score.*
FROM
(
SELECT items.*, AVG(reviews.score) as "averageScore" FROM "ITEM_VARIATION" as items
INNER JOIN "ITEM_REVIEW" as reviews ON reviews."FK_itemId"=items.id
GROUP BY items.id
) as score
INNER JOIN "ITEM_FOLLOWER" as follow ON score.id=follow."FK_itemId"
GROUP BY score.id
Inner Block works by itself and I believe I followed the same format.
However it outputs error:
ERROR: column "score.name" must appear in the GROUP BY clause or be used in an aggregate function
LINE 18: score.*
^
Is listing all the columns in score field only solution?
there are over 10 columns to list so I'd like to avoid that solution if it's not the only one
columns not included on the aggregation must be specified during group by
SELECT
COUNT(follow."FK_accountId"),
score.id,
score.name
FROM
(
SELECT items.id as id, items.name as name, AVG(reviews.score) as "averageScore" FROM "ITEM_VARIATION" as items
INNER JOIN "ITEM_REVIEW" as reviews ON reviews."FK_itemId"=items.id
GROUP BY items.id, items.name
) as score
INNER JOIN "ITEM_FOLLOWER" as follow ON score.id=follow."FK_itemId"
GROUP BY score.id, score.name
I would suggest you use correlated subqueries or a lateral join:
SELECT i.*,
(SELECT AVG(r.score)
FROM "ITEM_REVIEW" r
WHERE r."FK_itemId" = i.id
) as averageScore,
(SELECT COUNT(*)
FROM "ITEM_FOLLOWER" f
WHERE f."FK_itemId" = i.id
)
FROM "ITEM_VARIATION" i;
With the right indexes, this is probably faster as well.

Query all columns of table1 left join and count of the table2

I couldn't get this query working :
DOESN'T WORK
select
Region.*, count(secteur.*) count
from
Region
left join
secteur on secteur.region_id = Region.id
The solution I found is this but is there a better solution using joins or if this doesn't affect performance, because I have a very large dataset of about 500K rows
WORKS BUT AFRAID OF PERFORMANCE ISSUES
select
Region.*,
(select count(*)
from Secteur
where Secteur.Region_id = region.id) count
from
Region
I would suggest:
select region.*, count(secteur.region_id) as count
from region left join secteur on region.id = secteur.region_id
group by region.id, region.field2, region.field3....
Note that count(table.field) will ignore nulls, whereas count(*) will include them.
Alternatively, left join on a subquery and use coalesce to avoid nulls:
select region.*, coalesce(t.c, 0) as count
from region left join
(select region_id, count(*) as c from secteur group by region_id) t on region.id = t.region_id
I'd join region on an aggregate query of secteur:
SELECT r.*, COALESCE(s.cnt, 0)
FROM region r
LEFT JOIN (SELECT region_id, COUNT(*) AS cnt
FROM secteur
GROUP BY region_id) s ON s.region_id = r.id
I would go with this query:
select r.*,
(select count(*)
from Secteur s
where s.Region_id = r.id
) as num_secteurs
from Region r;
Then fix the performance problem by adding an index on Secteur(region_id):
create index idx_secteur_region on secteur(region_id);
You make a two mistakes
First: you have try to calulate COUNT() in only one (I mean, the second) table. This doesn't will work because theCOUNT(), like an any aggregate function, calculates only for the whole set of rows, not just for any part of the set (not only just for the one or an other joined table).
In your first query, you may replace secteur. * only by asterisk, like a Region.region_id, count(*) AS count, and do not forget add Region.region_id on the GROUP BY step.
Second: You has define not only aggregate function in the query, but and other fields: select Region.*, but you don't define them in GROUP BY step. You need to add to GROUP BY statement all columns, which you has define in the SELECT step but not apply an aggregate functions to them.
Append: not, GROUP BY Region.* doesn't will work, you should to define a columns in the GROUP BY step by their actual names.
So, correct form of this will looks like a
SELECT
Region.col1
,Region.col2,
, count(*) count
from Region
left join
secteur on secteur.region_id = Region.id
GROUP BY Region.col1, Region.col2
Or, if you don't want to type each name of column, use window queries
SELECT
Region.*,
, count( * ) OVER (PARTITION BY region_id) AS count
from Region
left join
secteur on secteur.region_id = Region.id

How to use count with Distinct ON

I have this query that already works, i need to write count query for this (need pagination), and i have issues using count with DISTINCT ON, anyone knows correct syntax and way to use it, i already googled but was not able to find any count queries with DISTINCT ON
As result i'm expecting total number of rows from this query that already works
select DISTINCT on (csd.team_contest_id)
c.id as contestId
from contest as c
left join company_sponsor_team as csd on csd.contest_id = c.id
left join sponsor as s on s.id = c.sponsor_id
left join team as d on d.id = c.team_id
left join player as m on c.creator_id = m.id
WHERE c.id = c.id
AND ((c.team_id is not null and c.sponsor_id is null and lower(d.name) LIKE LOWER(CONCAT('%TAN%')))
OR (c.team_id is not null and c.sponsor_id is not null and lower(s.name) LIKE LOWER(CONCAT('%TAN%')))
OR (c.team_id is null and lower(s.name) LIKE LOWER(CONCAT('%TAN%')))) AND (CURRENT_DATE < c.archive_date)
If you want to count the number of rows, use a subquery:
select count(*)
from ( <your query here> ) x;
If you have an aversion to subqueries, you can always do:
select count(distinct csd.team_contest_id)
from . . . <the rest of your query here>;
This returns the same value assuming that csd.team_contest_id is not NULL.

i want to modify this SQL statement to return only distinct rows of a column

select
picks.`fbid`,
picks.`time`,
categories.`name` as cname,
options.`name` as oname,
users.`name`
from
picks
left join categories
on (categories.`id` = picks.`cid`)
left join options
on (options.`id` = picks.oid)
left join users
on (users.fbid = picks.`fbid`)
order by
time desc
that query returns a result that like:
my question is.... I would like to modify the query to select only DISTINCT fbid's. (perhaps the first row only sorted by time)
can someone help with this?
select
p2.fbid,
p2.time,
c.`name` as cname,
o.`name` as oname,
u.`name`
from
( select p1.fbid,
min( p1.time ) FirstTimePerID
from picks p1
group by p1.fbid ) as FirstPerID
JOIN Picks p2
on FirstPerID.fbid = p2.fbid
AND FirstPerID.FirstTimePerID = p2.time
LEFT JOIN Categories c
on p2.cid = c.id
LEFT JOIN Options o
on p2.oid = o.id
LEFT JOIN Users u
on p2.fbid = u.fbid
order by
time desc
I don't know why you originally had LEFT JOINs, as it appears that all picks must be associated with a valid category, option and user... I would then remove the left, and change them to INNER joins instead.
The first inner query grabs for each fbid, the FIRST entry time which will result in a single entity for the FBID. From that, it re-joins to the picks table for the same ID and timeslot... then continues for the rest of the category, options, users join criteria of that single entry.
2 options, you could write a group by clause.
Or you could write a nested query joined back to itself to get pertinent info.
Nested aliased table:
SELECT
n.fBids
FROM
MyTable t
INNER JOIN
(SELECT DISTINCT fBids
FROM MyTable) n
ON n.ID = t.ID
Or group by option
SELECT fBId from MyTable
GROUP BY fBID
select picks.`fbid`, picks.`time`, categories.`name` as cname,
options.`name` as oname, users.`name` from picks left join categories
on (categories.`id` = picks.`cid`) left join options on (options.`id` = picks.oid)
left join users on (users.fbid = picks.`fbid`)
order by time desc GROUP BY picks.`fbid`
select
picks.fbid,
MIN(picks.time) as first_time,
MAX(picks.time) as last_time
from
picks
group by
picks.fbid
order by
MIN(picks.time) desc
However, if you want only distinct fbid's you cannot display cname and other columns at the same time.