I Have this query which works with the single limit imposed at the end.
select distinct
loc.mID,
loc.city,
loc.state,
loc.zip,
loc.country,
loc.latitude,
loc.longitude,
baseInfo.firstname,
baseInfo.lastname,
baseInfo.profileimg,
baseInfo.facebookID,
(((acos(sin(('37.816876'*pi()/180)) * sin((`latitude`*pi()/180))+cos(('37.816876'*pi()/180)) * cos((`latitude`*pi()/180)) * cos((('-121.285410' - `longitude`)*pi()/180))))*180/pi())*60*1.1515) AS `distance`,
teams.teamName,
teams.leagueType,
teams.teamType,
teams.subcat
FROM memb_geo_locations loc
left join memb_friends friends on (friends.mID = loc.mID or friends.friendID = loc.mID) and (friends.mID = '100018' or friends.friendID = '100018')
join memb_baseInfo baseInfo on baseInfo.mID = loc.mID
join memb_teams teams on teams.mID = loc.mID
where
loc.primaryAddress = '1'
and ((friends.mID is null or friends.friendID is null)
or (friends.isactive = 2))
and (
teams.teamName like '%Anaheim Ducks%'
or teams.teamName like '%San Jose Sharks%'
or teams.teamName like '%New England Patriots%'
or teams.teamName like '%New York Yankees%'
or teams.teamName like '%Orlando Magic%'
)
and loc.mID != 100018
having `distance` < 50
order by baseInfo.firstname
asc limit 30
However I want my results to be limited by the teamName to 3 results max per, And I have tried stuff to the extent of
select distinct
loc.mID,
loc.city,
loc.state,
loc.zip,
loc.country,
loc.latitude,
loc.longitude,
baseInfo.firstname,
baseInfo.lastname,
baseInfo.profileimg,
baseInfo.facebookID,
(((acos(sin(('37.816876'*pi()/180)) * sin((`latitude`*pi()/180))+cos(('37.816876'*pi()/180)) * cos((`latitude`*pi()/180)) * cos((('-121.285410' - `longitude`)*pi()/180))))*180/pi())*60*1.1515) AS `distance`,
teams.teamName,
teams.leagueType,
teams.teamType,
teams.subcat
FROM memb_geo_locations loc
left join memb_friends friends on (friends.mID = loc.mID or friends.friendID = loc.mID) and (friends.mID = '100018' or friends.friendID = '100018')
join memb_baseInfo baseInfo on baseInfo.mID = loc.mID
join memb_teams teams on teams.mID = loc.mID
where
loc.primaryAddress = '1'
and ((friends.mID is null or friends.friendID is null)
or (friends.isactive = 2))
and (
(select * from memb_teams where teamName like '%Buffalo Bills%' limit 2),
(select * from memb_teams where teamName like '%San Jose Sharks%' limit 2),
(select * from memb_teams where teamName like '%New England Patriots%' limit 2)
)
and loc.mID != 100018
having `distance` < 150
order by baseInfo.firstname
asc limit 30
With no success, usually just syntax errors.. or Operand Should 1 Column(s) so I am reaching out here hopefully someone can give me some idea how to refine my query a bit so I can limit the results to 3 per teamName.. rather than having staggered results where I could have 20 of one and 4 of another 2 of another and 1 and 1 (which is not desired). 3 or less per team is desired, Just don't know how. Ideas, that don't involve tackling a huge data set from the query and looping over it via server side code to output results I desire?
IN MSSQL I use ROW_NUMBER function, and it would be something like this:
SELECT * FROM dbo.MyTable WHERE recno
IN (SELECT recno FROM (SELECT Teamname, ROW_NUMBER() OVER (PARTITION BY Teamname ORDER BY recno DESC) AS intRow FROM dbo.MyTable) AS T
WHERE intRow IN (1,2,3))
recno=your unique record number
Basically your Subquery selects the top 3 records, adding a new "ROW NUMBER" column.
The Top Query selects all the records with Rownumber between 1 to 3.
I know there is no ROW_NUMBER() native function in MYSQL, so you could use this instead:
MySQL - Get row number on select
Related
Was wondering if there is a way to get the sum of the stock_case column for items with the same date_of_export ?
Updated with fiddle here and some relevant data:
https://www.db-fiddle.com/f/szC1Ftj3ZGEC24gSYp6ad4/4
The expected output would be this:
This is the query used
SELECT
st.product_code,
st.date_of_export,
st.best_before_date,
st.stock_case,
(
SELECT
SUM(st2.stock_case)
FROM
stock_tracking AS st2
WHERE
st2.product_code IN ('MGN003')
AND MONTH(st2.date_of_export) IN (07)
AND YEAR(st2.date_of_export) IN (2018)
AND st2.stock_case != 0
) AS total
FROM
stock_tracking st
WHERE
product_code IN ('MGN003')
AND MONTH(st.date_of_export) IN (07)
AND YEAR(st.date_of_export) IN (2018)
AND stock_case != 0
and my results
Would like to have a total column like 16, 16, 16, ... , 19, etc
For another case I used a subquery like so
SELECT
d.products_name,
stock_case,
st.date_of_export,
st.best_before_date,
st.product_code,
(SELECT
SUM(st2.stock_case)
FROM
stock_tracking AS st2
WHERE
DATE(st2.date_of_export) = (SELECT
DATE(tmp.last_update)
FROM
(SELECT
date_of_export AS last_update
FROM
stock_tracking
ORDER BY date_of_export DESC
LIMIT 1) AS tmp
WHERE
product_code = 'MGN003')) AS total
FROM
stock_tracking st
LEFT JOIN
products AS p ON p.products_model = st.product_code
LEFT JOIN
products_description AS d ON d.products_id = p.products_id
WHERE
product_code = 'MGN003'
AND d.language_id = 2
AND DATE(st.date_of_export) = (SELECT
DATE(tmp.last_update)
FROM
(SELECT
date_of_export AS last_update
FROM
stock_tracking AS st
ORDER BY date_of_export DESC
LIMIT 1) AS tmp)
with this result:
You can write a subquery to sum(stock_case) by date_of_export, then self join on Date, then you can get your expect result.
SELECT
s.product_name,
s.date_of_export,
s.best_before_date,
s.product_code,
s.stock_case,
t.totle
FROM
stock_tracking s
INNER JOIN
(
SELECT SUM(stock_case) totle,date_of_export dt
FROM stock_tracking
where
product_code = 'MGN003'
AND MONTH(date_of_export) =07
AND YEAR(date_of_export) =2018
AND stock_case != 0
GROUP BY date_of_export
) t on DATE_FORMAT(s.date_of_export, "%d-%m-%Y") = DATE_FORMAT(t.dt, "%d-%m-%Y")
where
s.product_code = 'MGN003'
AND MONTH(s.date_of_export) =07
AND YEAR(s.date_of_export) =2018
AND s.stock_case != 0
sqlfiddle
Without giving you the exact answer: You should think in the direction of:
SELECT SUM(column) FROM table WHERE ... GROUP BY date
or
SELECT SUM(column), DISTINCT date FROM table WHERE ...
So lookup the way GROUP BY and DISTINCT work :-)
I Have 2 tables, chamados(tickets) and atividades(activities) (1 for N)
Basically I need to select all 'chamados(tickets)' where last 'atividade(activity)' status is not 3 or 5;
I've tried within the SELECT and LEFT JOIN, nothing, I not got it yet.
My query is:
SELECT *
FROM (`chamados`)
ORDER BY `data_criacao_chamado` ASC
LIMIT 0,20;
I think that the query should seem something like:
SELECT *,
(
SELECT status FROM atividades WHERE atividade.fk_chamado = chamado.id_chamado ORDER BY id_atividade DESC LIMIT 1
) as status_item
FROM (`chamados`)
WHERE (status_item != 3 AND status_item != 5)
ORDER BY `data_criacao_chamado` ASC
LIMIT 0,20;
SELECT C.data_criacao_chamado FROM atividades A
JOIN
(SELECT fk_chamado, MAX(id_atividade) AS latest_atividade FROM atividades GROUP BY fk_chamado) LATEST_ATIVIDADES
ON A.fk_chamado = LATEST_ATIVIDADES.fk_chamado AND A.id_atividade = LATEST_ATIVIDADES.latest_atividade AND A.status_item NOT IN (3,5)
JOIN
chamados C ON C.id_chamado = A.fk_chamado
I'm uing the following query to give me a set of the last 20 matches for a team. I want to find their goals scored in the last 20 matches and order the results by (goals scored, date):
SELECT * FROM (
SELECT *, `against` AS `goalsF` , `for` AS `goalsA`
FROM `matches` , `teams` , `outcomes`
WHERE(
`home_team_id`=7 AND `matches`.away_team_id = `teams`.team_id
OR
`away_team_id`=7 AND `matches`.home_team_id = `teams`.team_id
)
AND `matches`.score_id = `outcomes`.outcome_id
ORDER BY `date` DESC
LIMIT 0 , 20
) res
ORDER BY `goalsF`
The problem is that:
if the team we're looking up is the home team, we need to count "goalsfor".
if the team ins the away team we need to count "goalsagainst" to find their for goals.
So what I need to be able to do is something like:
if (`home_team_id`=7 AND `matches`.away_team_id = `teams`.team_id)
SELECT *, `for` AS `goalsF` , `against` AS `goalsA`
if (`away_team_id`=7 AND `matches`.home_team_id = `teams`.team_id)
SELECT *, `against` AS `goalsF` , `for` AS `goalsA`
But, this must be peformed on the sub-set or results. I'm not sure if this is even possible, but it is beyond my knowledge of MYSQL.
Any help would be hugely appreciated.
Alan.
First, you really need to learn ANSI standard join syntax, where you put the join conditions in an on clause rather than a from clause. Also, aliases may a query much more readable.
The following does the logic that you want, although it does not include the team names:
SELECT *
FROM (SELECT *,
(case when m.home_team_id = 7 then o.against end) as `goalsF` ,
(case when m.away_team_id = 7 then o.`for` end) as `goalsA`
FROM `matches` m join
`outcomes` o
on m.score_id = o.outcome_id
WHERE m.home_team_id = 7 or m.away_team_id = 7
ORDER BY `date` DESC
LIMIT 0 , 20
) res
ORDER BY `goalsF`
To get the team names, you should join twice to the teams table, once for the home team and once for the away team. You can do this either in the subquery or afterwards. It is also a good idea to explicit mention the columns you are choosing and to include a table alias on every column reference:
SELECT *
FROM (SELECT m.*, o.*,
homet.team_name as hometeam_name, awayt.team_name as away_team_name,
(case when m.home_team_id = 7 then o.against end) as `goalsF` ,
(case when m.away_team_id = 7 then o.`for` end) as `goalsA`
FROM `matches` m join
`outcomes` o
on m.score_id = o.outcome_id join
teams homet
on homet.team_id = m.home_team_id join
teams awayt
on awayt.team_id = m.away_team_id
WHERE m.home_team_id = 7 or m.away_team_id = 7
ORDER BY `date` DESC
LIMIT 0 , 20
) res
ORDER BY `goalsF`
EDIT:
To get just goals for team 7, you can use:
(case when m.home_team_id = 7 then o.`for`
when m.away_team_id = 7 then o.against
end) as goals
To get goals for the other team:
(case when m.home_team_id = 7 then o.against
when m.away_team_id = 7 then o.`for`
end) as goals
EDIT II:
To get the "other" team name, the logic is similar. Replace the team name references in the select with:
(case when m.home_team_id = 7 then awayt.team_name
when m.away_team_id = 7 then homet.team_name
end) as goals
Suppose equity has a column called TickerID. I would like to replace the 111's with equity.TickerID. MySQL can't seem to resolve the scope and returns an unknown column when I try that. This SQL statement works but I need to run it for each ticker. Would be nice if I could get a full table.
SELECT Ticker,
IF(tbl_m200.MA200_Count = 200,tbl_m200.MA200,-1) AS MA200,
IF(tbl_m50.MA50_Count = 50,tbl_m50.MA50,-1) AS MA50,
IF(tbl_m20.MA20_Count = 20,tbl_m20.MA20,-1) AS MA20
FROM equity
INNER JOIN
(SELECT TickerID,AVG(Y.Close) AS MA200,COUNT(Y.Close) AS MA200_Count FROM
(
SELECT Close,TickerID FROM equity_pricehistory_daily
WHERE TickerID = 111
ORDER BY Timestamp DESC LIMIT 0,200
) AS Y
) AS tbl_m200
USING(TickerID)
INNER JOIN
(SELECT TickerID,AVG(Y.Close) AS MA50,COUNT(Y.Close) AS MA50_Count FROM
(
SELECT Close,TickerID FROM equity_pricehistory_daily
WHERE TickerID = 111
ORDER BY Timestamp DESC LIMIT 50
) AS Y
) AS tbl_m50
USING(TickerID)
INNER JOIN
(SELECT TickerID,AVG(Y.Close) AS MA20,COUNT(Y.Close) AS MA20_Count FROM
(
SELECT Close,TickerID FROM equity_pricehistory_daily
WHERE TickerID = 111
ORDER BY Timestamp DESC LIMIT 0,20
) AS Y
) AS tbl_m20
USING(TickerID)
This seems to be some bug or "feature" of MySQL. Many persons seems to have the same problem with outer tables being out of scope.
Anyway... You could create functions that retrieve the information you want:
DROP FUNCTION IF EXISTS AveragePriceHistory_20;
CREATE FUNCTION AveragePriceHistory_20(MyTickerID INT)
RETURNS DECIMAL(9,2) DETERMINISTIC
RETURN (
SELECT AVG(Y.Close)
FROM (
SELECT Z.Close
FROM equity_pricehistory_daily Z
WHERE Z.TickerID = MyTickerID
ORDER BY Timestamp DESC
LIMIT 20
) Y
HAVING COUNT(*) = 20
);
SELECT
E.TickerID,
E.Ticker,
AveragePriceHistory_20(E.TickerID) AS MA20
FROM equity E;
You would get NULL instead of -1. If this is undesirable, you could wrap the function-call with IFNULL(...,-1).
Another way of solving this, would be to select for the time-frame, instead of using LIMIT.
SELECT
E.TickerID,
E.Ticker,
(
SELECT AVG(Y.Close)
FROM equity_pricehistory_daily Y
WHERE Y.TickerID = E.TickerID
AND Y.Timestamp > ADDDATE(CURRENT_TIMESTAMP, INTERVAL -20 DAY)
) AS MA20
FROM equity E;
I have the following tables in my game's database:
rankedUp (image_id, user_id, created_at)
globalRank (image_id, rank )
matchups (user_id, image_id1, image_id2)
All image_ids in globalRank table are assigned a rank which is a float from 0 to 1
Assuming I have the current logged in user's "user_id" value, I'm looking for a query that will return a pair of image ids (imageid1, imageid2) such that:
imageid1 has lower rank than imageid2 but is also the next highest rank less than imageid2
matchups table doesn't have (userid,imageid1,imageid2) or (userid,imageid2,imageid1)
rankedup table doesn't have (userid,imageid1) or if it does, the createdat column is older than X hours
What I have so far for requirement 1 is this:
SELECT lowerImages.image_id AS lower_image, higherImages.image_id AS higher_image
FROM global_rank AS lowerImages, global_rank AS higherImages
WHERE lowerImages.rank < higherImages.rank
AND lowerImages.image_id = (
SELECT image_id
FROM (
SELECT image_id
FROM global_rank
WHERE rank < higherImages.rank
ORDER BY rank DESC
LIMIT 1 , 1
) AS tmp
)
but it doesnt work because I can't reference higherImages.rank in the subquery.
Does anyone know how I could satisfy all of those requirements in one query?
Thanks for your help
EDIT:
I now have this query but I don't know about the efficiency and I need to test it for correctness:
SELECT lowerImages.image_id AS lower_image,
max(higherImages.image_id) AS higher_image
FROM global_rank AS lowerImages, global_rank AS higherImages
WHERE lowerImages.rank < higherImages.rank
AND 1 NOT IN (select 1 from ranked_up where
lowerImages.image_id = ranked_up.image_id
AND ranked_up.user_id = $user_id
AND ranked_up.created_at > DATE_SUB(NOW(), INTERVAL 1 DAY))
AND 1 NOT IN (
SELECT 1 from matchups where user_id = $userId
AND lower_image_id = lowerImages.image_id
AND higher_image_id = higherImages.image_id
UNION
SELECT 1 from matchups where user_id = $user_id
AND lower_image_id = higherImages.image_id
AND higher_image_id = lowerImages.image_id
)
GROUP BY 1
the "not in" statements I'm using are all indexed so they should run fast. The efficiency problem I have is the group by and selection of the global_rank tables
This question is a revision of Pretty Complex SQL Query, which should no longer be answered.
select
(
select image_id, rank from
rankedup inner join globalRank
on rankedup.image_id = globalRank .image_id
where user_id = XXX
limit 1, 1
) as highest,
(
select image_id, rank from
rankedup inner join globalRank
on rankedup.image_id = globalRank .image_id
where user_id = XXX
limit 2, 1
) as secondhighest
I normally use SQL Server, but this i think is the translation for mysql :)
This should do the trick:
SELECT lowerImages.*, higherImages.*
FROM globalrank AS lowerImages, globalrank AS higherImages
WHERE lowerImages.rank < higherImages.rank
AND lowerImages.image_id = (
SELECT image_id
FROM (
SELECT image_id
FROM globalrank
WHERE rank < higherImages.rank
ORDER BY rank DESC
LIMIT 1,1
) AS tmp
)
AND NOT EXISTS (
SELECT * FROM matchups
WHERE user_id = $user_id
AND ((image_id1 = lowerImages.image_id AND image_id2 = higherImages.image_id)
OR (image_id2 = lowerImages.image_id AND image_id1 = higherImages.image_id))
)
AND higherImages.image_id NOT IN (
SELECT image_id FROM rankedup
WHERE created_at < DATE_ADD(NOW(), INTERVAL 1 DAY)
AND USER_ID <> $user_id
)
ORDER BY higherImages.rank
I'm assuming the PKs of matchups and rankedup include all columns in those tables. This would allow the second 2 sub-queries to utilize the PK indexes. You would probably want an ordered index on globalrank.rank to speed up the first sub-query.