sort by MySQL special group - mysql

Table A shows results that I have by running the following SQL in MySQL.
SELECT * FROM table
WHERE MATCH (title) AGAINST ('marka tv')
Table A
Table B shows results that I want to get. As you can see the groups are in round-robin order.
Table B

If I understand the question, you want to sort the output so the groups are in a round-robin fashion rather than ordered. You can do this by enumerating the values within each group and then using that information for sorting:
SELECT t.*
FROM (SELECT t.*,
(#rn := if(#g = groups, #rn + 1,
if(#g := groups, 1, 1)
)
) as rn
FROM table t CROSS JOIN
(SELECT #rn := 0, #g := '') params
WHERE MATCH (title) AGAINST ('marka tv')
ORDER BY groups
) t
ORDER BY rn, groups;

Consider a subquery in a derived table to calculate a group number to be sorted at final table:
SELECT f.*
FROM
(SELECT t1.* ,
(SELECT count(*)
FROM table t2
WHERE (t2.title <= t1.title)
AND (t1.groups = t2.groups)) AS groupNo
FROM table t1
WHERE MATCH (t1.title) AGAINST ('marka tv')
) AS f
ORDER BY groupNo, groups

Related

MySql Query to find out first 50% of records from a Table

I am trying to fetch first 50% of records from a MySQL Table User. I know we can use limit or top for finding them but the total number of records are not fixed so hard coding the actual number in the limit or top doesn't gives me first 50% of records. How can I achieve this?
If you are running MySQL 8.0, you can use window functions for this: ntile() does exactly what you ask for. Assuming that your ordering column is id:
select *
from (select t.*, ntile(2) over(order by id) nt from mytable) t
where nt = 1
In earlier versions, one option is a user variable and a join with an aggregate query:
select *
from (
select t.*, #rn := #rn + 1 rn
fom (select * from mytable order by id) t
cross join (select #rn := 0) x
cross join (select count(*) cnt from mytable) c
) t
where rn <= cnt / 2
Mysql directly not supports this. You can try with two queries or use subqueries
Something like this.
find the count of total records/2
that value has to be applied in the limit clause.
SET #count = (SELECT COUNT(*)/2 FROM table);
SET #sql = CONCAT('SELECT * FROM table LIMIT ', #count);
SELECT * FROM table name LIMIT (select COUNT(*)/2 from table name);

How can I update a surrogate key based on an older entry of a table

I have a table called player_stage.
I am trying to prepare my data so I can put it into a data warehouse.
I currently have a unreliable work-around that involves a duplicates view and handpicking the values from the duplicates.
I need to create a query that gives duplicates the same surrogate key(sk).
Any idea how I can do this? I've been stuck on t
his for 3 days.
If you are using MySQL 8+, then DENSE_RANK can work here:
SELECT
PLAYER_ID,
PLAYER_NAME,
DB_SOURCE,
DENSE_RANK() OVER (ORDER BY PLAYER_NAME) SK
FROM yourTable;
The above call to DENSE_RANK would assign the same SK value to all records belonging to the same player name.
If you are using a version of MySQL earlier than 8+, then we can simulate the dense rank with user variables, e.g.
SELECT t1.PLAYER_ID, t1.PLAYER_NAME, t1.DB_SOURCE, t2.rn AS SK
FROM yourTable t1
INNER JOIN
(
SELECT PLAYER_NAME, #rn := #rn + 1 AS rn
FROM (SELECT DISTINCT PLAYER_NAME FROM yourTable) t, (SELECT #rn := 0) r
ORDER BY PLAYER_NAME
) t2
ON t1.PLAYER_NAME = t2.PLAYER_NAME
ORDER BY
t1.PLAYER_ID;
Demo

Is there a way to list distinct field results from multiple columns

I have a few tables where I want to look at distinct values for a number of fields within them.
Eg.
ID | Category | sub_category | item
Is there a way where I can return a unique result set for each field?
Essentially I just want to see all distinct values for a different columns in a table within one result set.
I've tried joins but i need the results to be mutually exclusive of one another.
Each returned field won't necessarily have the same matching number of rows either.
Can you just use union all?
select distinct 'category', category
from t
union all
select distinct 'subcategory', subcategory
from t;
EDIT:
If you want the values in different columns:
select c.category, s.subcategory
from (select category, row_number() over (order by category) as seqnum
from t
group by category
) c full join
(select subcategory, row_number() over (order by subcategory) as seqnum
from t
group by subcategory
) s
on c.seqnum = s.seqnum;
You can extend this for additional columns by adding more subqueries and full joins.
EDIT II:
Older versions of MySQL support neither window functions nor full join. You can do something similar, enumerating each value and then aggregating:
select max(category) as category,
max(subcategory) as subcategory
from ((select (#rnc := #rnc + 1), category, null as subcategory
from (select distinct category from t
) c cross join
(select #rnc := 0) params
) union all
(select (#rns := #rns + 1), null as category, subcategory
from (select distinct subcategory from t
) s cross join
(select #rns := 0) params
)
) sc
group by rn;

How can I select from in other select in MYSQL query?

How can I select from in other select in MYSQL query?
Something like this
SET #row_number = 0;
SELECT a.num FROM
(SELECT
(#row_number:=#row_number + 1) AS num, id
FROM
main) as a where a.id=6
I want to know the number of records where id=6 if it's the first row, second row or third one
If your query has the filter where a.id = 6, then the row with id = 6 will always be the first row of the result set.
I am interpreting your question to mean: "if I sorted by id ascending, what row number is the row with id = 6 going to be on". If so, you can use a simple aggregation:
SELECT COUNT(*)
FROM main m
WHERE m.id <= 6;
Your query seems inspired by enumerating all the rows. You could do this version as well:
select m.*
from (select m.*, (#rn := #rn + 1) as rn
from main m cross join
(select #rn := 0) params
order by id
) m
where id = 6;
The first version should be more efficient, particularly with an index on id.

Automate MySQL fields (like Excel)

Say I have a table like ID, NAME, SCORE. Now normally, to get the rankings of the teams, I'd select all and order by. Sometimes though, I don't want to know all the rankings, just the ranking of one team. If I added a column RANK, is there any way for MySQL to automatically fill in those values for me based off of SCORE? (I believe MS Excel has this capability)
and if so, how does it handle ties?
thanks
You can calculate the rankings when you make your query:
SELECT * FROM (
SELECT teams.*, #rownum := #rownum + 1 AS rank
FROM teams, (SELECT #rownum := 0) T1
ORDER BY score DESC) T2
WHERE id = 1
It works by initializing a variable called rownum to 0 and then iterating over the rows in order of decreasing score. For each team the rownum is increased and the team is assigned a rank based on the current value of rownum. The outer select applies a where clause so that only one row is returned.
Here is an improved version that assigns the same rank to teams that have tied scores:
SELECT id, name, teams.score, rank FROM (
SELECT score, #rownum := #rownum + 1 AS rank
FROM (SELECT DISTINCT(score) FROM teams) T1, (SELECT #rownum := 0) T2
ORDER BY score DESC) T3
JOIN teams ON T3.score = teams.score
If this isn't fast enough for you, then use a trigger instead.
looks like I'm looking for a MySQL trigger
Get All Teams:
SELECT
s1.name,
s1.score,
COUNT(s2.name) + 1 AS rank
FROM scores s1
LEFT OUTER JOIN scores AS s2 ON (s1.score < s2.score)
GROUP BY s1.name
ORDER BY COUNT(s2.name)
Get One Team ('The Canucks'):
SELECT
s1.name,
s1.score,
COUNT(s2.name) + 1 AS rank
FROM scores s1
LEFT OUTER JOIN scores AS s2 ON (s1.score < s2.score)
GROUP BY s1.name
HAVING s1.name = 'The Canucks'
ORDER BY COUNT(s2.name)
The method shown in the above examples get the ranking dynamically (not filling a regular or temp table).
Note: both of these assume a given team only exists once in scores table for the rank value to be correct.