Sum of the sequence between two numbers MySQL [closed] - mysql

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I have the following table;
I want to get the sum of the sequence between the col1 and col2. So for example first row should be sum(7,8,9,10,11,12). Something similar to sum(seq(col1,col2)).
Can you please help me to write this in MySQL?

As we know the sum of N natural numbers would be n * (n + 1) / 2. Use the same concept to determine the sum of your columns.
Let's say col1 = 6 and col2 = 8, and as mentioned in comment col1 < col2, so the answer would be
Sum = Sum of (8) natural numbers - Sum of (6-1) natural numbers
SELECT
id,
col1,
col2,
(col2 * (col2 + 1) / 2) - ((col1 - 1) * col1 /2) Sum_Of_Col1_Col2
FROM table_name;

Something like this:
SELECT CASE WHEN MOD((col2-col1)/2)>0 THEN (col1+col2)*(col2-col1+1)/2 ELSE (col1+col2)*(col2-col1)/2+(col2+col1)/2 END AS col_sum
FROM yourTable

Your question might be a little hard to swing if you table doesn't also have some sort of ID or other unique column, so let's add that first:
id | col1 | col2
1 | 7 | 12
2 | 8 | 10
3 | 6 | 8
We can handle this via the "calendar table" approach, where in this case the calendar table just contains a sequence from 1 to however large the values can get. For example, in MySQL 8+ we can try:
WITH nums AS (
SELECT 1 AS val UNION ALL
SELECT 2 UNION ALL
...
SELECT 12
)
SELECT
t.id,
SUM(n.val) AS sum
FROM yourTable t
LEFT JOIN nums n
ON n.val BETWEEN t.col1 AND t.col2
GROUP BY
t.id
ORDER BY
t.id;
Demo
Note that there are better ways to generate a sequence table in MySQL other than a raw CTE, but this might the topic of a different question.

For your specific case where col2 > col1, there is a formula for summing up an arithmetic progression between two numbers. I have implemented it below
select ((col2−col1+1)*(col1+col2))/2 end as seq_sum
from your_table
Can also be expressed as:
select (square(col2)-square(col1)+col1+col2)/2 end as seq_sum
from your_table

Related

mySQL: Select first number not in subquery results [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have a column itemId that contains unique IDs in the format US001, US002, US003 etc.
The trailing numbers of these IDs are not consecutive as rows may have been deleted.
I am looking for a way to find the first number that DOES NOT EXIST in my column.
Example 1:
Column: US001, US002, US004, US006.
Expected result: 3.
Example 2:
Column: US001, US002, US003, US004, US007.
Expected result: 5.
Example 3:
Column: US001, US002, US003, US004, US005.
Expected result: 6.
I tried the following but this returns NULL or no results (also no error):
SELECT MIN((RIGHT(i.itemId, 3)) + 1) AS nextAvailableId
FROM items i
WHERE RIGHT(i.itemId, 3) NOT IN
(
SELECT * FROM
(
SELECT RIGHT(i2.itemId, 3) AS itemNo
FROM items i2
) AS x
)
Can anyone please help me with this ?
Thanks,
Tim
Here is one option using window functions and string functions:
select min(id) + 1 as nextAvailableId
from (
select substr(itemid, 2) as id,
lead(substr(itemid, 2)) over(order by substr(itemid, 2)) as lead_id
from mytable t
) t
where lead_id > id + 1 or lead_id is null
In MySQL 5.x, where string functions are not available, you can use a subquery:
select min(substr(itemid, 2)) + 1 as nextAvailableId
from mytable
where not exists (
select 1
from mytable t1
where substr(t1.itemid, 2) = substr(t.itemid, 2) + 1
)

SQL sort column A & update column B

I have a table with data similar to:
Inven DESCRIPT PrintOrder
---------------------------------
1 D 9
2 B 0
3 A 5
4 Z 0
5 X 1
. . .
. . .
. . .
I would like to sort the table on column DESCRIPT descending alpha (A - Z) and then update the column PRINTORDER so that when done, the record with PRINTORDER = 1 is the the highest alpha (A) and the record with the highest value for PRINTORDER will be the lowest in alpha (Z).
Is this possible without using temporary columns? Not a deal breaker if not, just a preference.
DESIRED RESULT:
To update the PrintOrder values based on the sorting result
Inven DESCRIPT PrintOrder
---------------------------------
1 D 3
2 B 2
3 A 1
4 Z 5
5 X 4
I am unclear whether you want to modify the table or just create a result set. Here is the solution to the latter using standard SQL:
select Inven, Descript, row_number() over (order by Descript) as PrintOrder
from table t
order by Descript;
EDIT:
In MySQL, the select would look like:
select t.*
from (select Inven, Descript, (#rn := #rn + 1) as PrintOrder
from table t cross join (select #rn := 0) params
order by Descript
) t
order by Inven;
The update is slightly trickier, because you cannot sort and initialize a variable:
update t
set PrintOrder = (#rn := coalesce(#rn + 1, 1))
order by Descript;
This should do it:
Update T
set PRINTORDER = ASCII(UPPER(DESCRIPT)) - 64
while the ASCII of A is 65 in your system. :)
EDIT:
As you said there might be something more, so we need to change it a bit by assuming you have a PK column name as Id:
UPDATE T
set PRINTORDER = T2.Order
FROM T
INNER JOIN (SELECT IDENTITY(int, 1,1) AS Order,Id FROM T Order By DESCRIPT ASC) T2 ON T.Id=T2.Id
But in this way even two record has same DESCRIPT would end up have different printorder, it could be a bit more complex if you want keep them the same.
EDIT:
Sorry just realized you are using MySql, the IDENTITY(int, 1,1) is from SQL Server, basically it generate a row number, you might need something different to have one: http://blog.sqlauthority.com/2014/03/08/mysql-generating-row-number-for-each-row-using-variable/
After arriving at my office, and chatting with my colleague, the question posed is completely inaccurate. So I'll close this thread, and an open a new one with a more accurate description of the issue.
Thank you Gordon & Simon for your responses, they are most appreciated.

Mysql recursive substracting and multiplying grouped values

Couldn't really explain my problem with words, but with an example I can show it clearly:
I have a table like this:
id num val flag
0 3 10 1
1 5 12 2
2 7 12 1
3 11 15 2
And I want to go through all the rows, and calculate the increase of the "num", and multiply that difference with the "val" value. And when I calculated all of these, I want to add these results together, but grouped based on the "flag" values.
This is the mathematical equation, that I want to run on the table:
Result_1 = (3-0)*10 + (7-3)*12
Result_2 = (5-0)*12 + (11-5)*15
78 = Result_1
150 = Result_2
Thank you.
Interesting question. Unfortunately MYSQL doesn't support recursive queries, so you'll need to be a little creative here. Something like this could work:
select flag,
sum(calc)
from (
select flag,
(num-if(#prevflag=flag,#prevnum,0))*val calc,
#prevnum:=num prevnum,
#prevflag:=flag prevflag
from yourtable
join (select #prevnum := 0, #prevflag := 0) t
order by flag
) t
group by flag
SQL Fiddle Demo

Oracle/MYSQL: Sort records from a select query on a column that contains alphanumeric values

I know that this question has been asked in various forms but my requirement happens to be a bit different.
Suppose I have a table that contains data as follows:
ID NAME VALUE
-----------------------------
1 ABC-2-2 X
2 PQRS-1-3 Y
3 ABC-3-2 Z
4 PQRS-1-4 A
5 PQRS-3-4 B
6 MNO-2-1 C
7 AAA-1 D
8 BBB-2 E
9 CCC-3 F
Now, the output that I'm expecting should look something like this:
ID NAME VALUE
-----------------------------
7 AAA-1 D
2 PQRS-1-3 Y
4 PQRS-1-4 A
8 BBB-2 E
6 MNO-2-1 C
1 ABC-2-2 X
9 CCC-3 F
3 ABC-3-2 Z
5 PQRS-3-4 B
Note that this is not a direct alpha-numeric sort. Instead, the value before the first "-" is ignored and the fields are sorted on what is after the first "-" in the name.
I'm not very familiar with PL/SQL and any kind of help on this would be appreciated.
Thanks.
PS: Note that this should work on both Oracle and MySQL.
For your example this would suffice (Oracle syntax):
ORDER BY SUBSTR(name,4)
If the number of characters before the first hyphen can vary, you can do this (again Oracle syntax):
ORDER BY SUBSTR(name,INSTR(name,'-')+1)
However that won't work if you have codes like:
AAA-10-1
AAA-8-1
AAA-9-1
and expect AAA-10-1 to appear after AAA-9-1. Then you will need to parse it further:
ORDER BY LPAD(SUBSTR(name,INSTR(name,'-')+1, INSTR(name,'-',1,2)-INSTR(name,'-')-1),10,'0'),
LPAD(SUBSTR(name,INSTR(name,'-',1,2)+1),10,'0')
(NB I have used LPAD(x,10,'0') to turn a value like '1' into '0000000001' and so on, rather than use TO_NUMBER since this could fail if there are any non-numerics in your data.)
Example:
with data as
(
select 'AAA-1' name from dual
union all
select 'PQR-1-4' name from dual
union all
select 'PQR-1-3' name from dual
union all
select 'AAA-10-10' name from dual
union all
select 'AAA-10-1' name from dual
union all
select 'AAA-9-10' name from dual
union all
select 'AAA-9-1' name from dual
)
select *
from data
ORDER BY LPAD(SUBSTR(name,INSTR(name,'-')+1, INSTR(name,'-',1,2)-INSTR(name,'-')-1),10,'0'),
LPAD(SUBSTR(name,INSTR(name,'-',1,2)+1),10,'0');
Output:
NAME
---------
PQR-1-3
PQR-1-4
AAA-9-1
AAA-9-10
AAA-10-1
AAA-10-10
AAA-1
And if AAA-1 should come first:
ORDER BY LPAD(SUBSTR(name,INSTR(name,'-')+1, INSTR(name||'-','-',1,2)-INSTR(name,'-')-1),10,'0'),
LPAD(SUBSTR(name,INSTR(name||'-','-',1,2)+1),10,'0') nulls first
Not sure about mysql syntax, but you can do this in oracle:
select * from <your_table>
order by substr(name, 5)
in mssql the syntax of finding your problem is :
select * from mytable order by substring(name,PATINDEX('%-%',name)+1,len(name)-PATINDEX('%-%',name))
SqlFiddle

How do I find the row where a certain value is between 2 others?

So, I have a mysql table that looks roughly like this, where the first 2 columns contain ranges.
1 , 5 , Value1
6 , 14 , Value2
14 , 18 , Value3
How can I query to find which row a certain value falls between (ie, if I have 9, it returns Value2; if I have 2, it returns Value1). This table is about 10mb big, so the more efficient, the better.
Thanks!
Actually it's almost the same as madgnome's answer, however IMO a bit cleaner:
SELECT ... WHERE 9 BETWEEN min_value AND max_value;
SELECT
val
FROM
table
WHERE
table.range_min <= 9
AND table.range_max >= 9
/* OR 9 BETWEEN table.range_min AND table.range_max*/
For efficiency add an index for range_min and range_max column.
where fielda >= 9 and fieldb <= 9
add a index that contain this 2 field on your table
select col3 from thetable where 2 between col1 and col2
You'd like a combined index on col1 and col2 for this to perform well.