I have a table that looks like this:
ID Damage
1 10
2 7
3 153587
4 1
...1M more rows
I have another table that has a column that represents the percentile in the amount of rows I need to grab, so if its top 10 percentile the column value will be 100000 I want to grab based on damage.
Is there a way instead of saying LIMIT 100000, since the percentile changes to replace 100000 with essentially a variable or the column value?
Second table:
Days Percentile_Affected Damage_Sum
14 87000
30 161000
90 371000
...
If the ids had no gaps, you could just use the id. Instead, you can add a counting variable and use that:
select t.*
from (select t.*, (#rn := #rn + 1) as rn
from (select t.*
from t
order by id
) t cross join
(select #rn := 0) params
) t
where rn < (select "a column" from "another table");
The alternative is to construct the query and use dynamic SQL:
select #sql := replace('select t.* from t limit [limit]', [limit], "a column")
from "another table";
prepare stmt from #sql;
execute stmt;
Or, use a placeholder for the limit:
set #sql = 'select t.* from t limit ?';
select #limit := "a column"
from "another table";
prepare stmt from #sql;
execute stmt using #limit;
Related
I want to use a select statement to control the limit of another select query, I cant get it to work, what I have below. The Select in the braces returns an INT.
Im newer to MySQL so im not sure what I should use instead to get this to work.
SELECT *
FROM `tbl_prod`
WHERE prod_id = 32
ORDER BY prod_level ASC , prod_date
LIMIT
(SELECT max_count
FROM Prod_subscription
WHERE prod_id = 32)
You can't write subquery in LIMIT, but you can use dynamic SQL to make your expected result.
SET #num = (
SELECT max_count
FROM Prod_subscription
WHERE prod_id = 32);
PREPARE STMT FROM 'SELECT *
FROM `tbl_prod`
WHERE prod_id = 32
ORDER BY prod_level ASC , prod_date
LIMIT ?';
EXECUTE STMT USING #num;
I tried two methods but failed in mysql.
/*see top 50% students, but this sql can't work*/
select * from student_table order by chinese_score desc limit count(*) * 0.5 ;
/*also can't work*/
set #num= floor((select count(*) from test.student_score)*0.5);
select * from student_table order by chinese_score desc limit #num ;
How to solve in mysql?
In Mysql this can be done in a single query using user defined variables.
You can store a value in a user-defined variable in one statement and
refer to it later in another statement. This enables you to pass
values from one statement to another.
SELECT * FROM (
SELECT student_table.*, #counter := #counter +1 AS counter
FROM (SELECT #counter:=0) AS initvar, student_table
ORDER BY student_table.chinese_score DESC
) AS result
WHERE counter < (#counter/2) ORDER BY chinese_score DESC;
The following statement outputs the userName and week1Score. I would like it to loop through 17 times, to get the score for each of the 17 weeks.
SELECT userName, (totalWins+(totalPushs*.5)) AS week1Score FROM (
SELECT *, SUM(win) AS totalWins, SUM(lost) AS totalLost, SUM(push) AS totalPushs FROM (
SELECT *, (finalResult = 'win') AS win, (finalResult = 'loss') AS lost, (finalResult = 'push') AS push FROM (
SELECT userName, IF (pickID=visitorID, visitorResult, homeResult) AS finalResult
FROM table_users
JOIN table_picks
ON table_users.userID = table_picks.userID
JOIN table_schedule
ON table_picks.gameID = table_schedule.gameID
WHERE weekNum = 1
) x
) x GROUP BY userName
) x ORDER BY userName
The above statement outputs the following.
+-----------------------+
| userName | week1Score |
+-----------------------+
I would like it to loop through 17 times to to output the following.
+------------------------------------------------------------------------+
| userName | week1Score | week2Score | week3Score | week4Score | week... |
+------------------------------------------------------------------------+
How would I use MySQL loop to do this?
I think your query is a bit complex. However, there's a better approach: a Pivot Query.
MySQL does not have a "pivot" instruction, but an expression can be built to get the output you need.
I'll build a temp table to make things a bit easier to read (I am using user variables to make things a bit clearer):
-- This first table will compute the score
drop table if exists temp_step01;
create temporary table temp_step01
select userId
, userName
, weekNum
, #finalResult := if(pickId=visitorId, visitorResult, homeResult) as finalResult
, #w := #finalResult = 'win' as win
, #l := #finalResult = 'loss' as lost
, #p := #finalResult = 'push' as push
, #w + (#p * 0.5) as score
from
table_users as tu
join table_picks as tp on tu.userId = tp.userId
join table_schedule as ts on tp.gameId = ts.gameId;
alter table temp_step01
add index uid(userId),
add index wn(weekNum);
Now, the fun part: build the pivot table
-- First, build the expression for each column
select
group_concat(
concat(
'sum(case weekNum when ', weekNum, ' then score end) as week', weekNum, 'score'
)
)
into #sql
from (select distinct weekNum from temp_step01) as a;
-- Then, create a complete SELECT statement
set #sql = concat('select userId, userName, ', #sql, ' from temp_step01 group by userId');
-- OPTIONAL: Check that the sql statement is well written:
select #sql;
-- Now, prepare a statement, and execute it
prepare stmt from #sql;
execute stmt;
-- When you're done, don't forget to deallocate the statement
deallocate prepare stmt;
A bit laborious, but I think this will give you what you need. Hope it helps.
Is it possible to store the result of a prepared table in mysql ?
My use case is -:
I am creating two variables based on certain conditions of the source table, then fetching the randomized rows, based on this criteria. Since I have 10 of such tables, should I be 1st joining them and then doing this randomization on the "overall" passing/filtering criteria (See also #total below, which is my main criteria, PER table)
set #total=(select count(*) from tab_1 where predict_var ="4" or predict_var ="2" ) ;
set #sample= ( select #total*(70/30)) ;
PREPARE STMT FROM " SELECT * FROM tab_1 WHERE predict_var = '4' or predict_var = '2' union
(SELECT * FROM tab_1 WHERE predict_var = '0' or predict_var = '1' ORDER BY RAND() limit ? )" ;
EXECUTE STMT USING #sample;
After I have Executed this statement - I want to be storing these rows, for retrieval later, preferably in form of a table. I would like to do something like this
# incorrect syntax, but I would like something similar
create table tab_derived_1
select * from
EXECUTE STMT USING #sample;
Tip : +1 for additionally mentioning, why this does not work with prepared Statements.
Put the create table in the statement:
PREPARE STMT FROM "CREATE TABLE tab_derived_1 SELECT * FROM tab_1 WHERE predict_var = '4' or predict_var = '2' union
(SELECT * FROM tab_1 WHERE predict_var = '0' or predict_var = '1' ORDER BY RAND() limit ? )" ;
EXECUTE STMT USING #sample;
And if you want to return the results, not just store them in a table, just do a final
SELECT * FROM tab_derived_1
I have a table with records and it has a row called category. I have inserted too many articles and I want to select only two articles from each category.
I tried to do something like this:
I created a view:
CREATE VIEW limitrows AS
SELECT * FROM tbl_artikujt ORDER BY articleid DESC LIMIT 2
Then I created this query:
SELECT *
FROM tbl_artikujt
WHERE
artikullid IN
(
SELECT artikullid
FROM limitrows
ORDER BY category DESC
)
ORDER BY category DESC;
But this is not working and is giving me only two records?
LIMIT only stops the number of results the statement returns. What you're looking for is generally called analytic/windowing/ranking functions - which MySQL doesn't support but you can emulate using variables:
SELECT x.*
FROM (SELECT t.*,
CASE
WHEN #category != t.category THEN #rownum := 1
ELSE #rownum := #rownum + 1
END AS rank,
#category := t.category AS var_category
FROM TBL_ARTIKUJT t
JOIN (SELECT #rownum := NULL, #category := '') r
ORDER BY t.category) x
WHERE x.rank <= 3
If you don't change SELECT x.*, the result set will include the rank and var_category values - you'll have to specify the columns you really want if this isn't the case.
SELECT * FROM (
SELECT VD.`cat_id` ,
#cat_count := IF( (#cat_id = VD.`cat_id`), #cat_count + 1, 1 ) AS 'DUMMY1',
#cat_id := VD.`cat_id` AS 'DUMMY2',
#cat_count AS 'CAT_COUNT'
FROM videos VD
INNER JOIN categories CT ON CT.`cat_id` = VD.`cat_id`
,(SELECT #cat_count :=1, #cat_id :=-1) AS CID
ORDER BY VD.`cat_id` ASC ) AS `CAT_DETAILS`
WHERE `CAT_COUNT` < 4
------- STEP FOLLOW ----------
1 . select * from ( 'FILTER_DATA_HERE' ) WHERE 'COLUMN_COUNT_CONDITION_HERE'
2. 'FILTER_DATA_HERE'
1. pass 2 variable #cat_count=1 and #cat_id = -1
2. If (#cat_id "match" column_cat_id value)
Then #cat_count = #cat_count + 1
ELSE #cat_count = 1
3. SET #cat_id = column_cat_id
3. 'COLUMN_COUNT_CONDITION_HERE'
1. count_column < count_number
4. ' EXTRA THING '
1. If you want to execute more than one statement inside " if stmt "
2. IF(condition, stmt1 , stmt2 )
1. stmt1 :- CONCAT(exp1, exp2, exp3)
2. stmt2 :- CONCAT(exp1, exp2, exp3)
3. Final "If" Stmt LIKE
1. IF ( condition , CONCAT(exp1, exp2, exp3) , CONCAT(exp1, exp2, exp3) )
share
Use group by instead of order by.