-1

I have the following tables:

Stocks

id name amount
1 Pen 35
2 Cd 21
3 Bag 15

StockUnits

id name include stockid
1 onepen 1 1
2 dozen 6 1
3 pocket 24 1
4 onecd 1 2
5 pocket 5 2
6 onebag 1 3

So how do I get a result like the following with SELECT query?
stock unit qty
Pen onepen 5
Pen dozen 1
Pen pocket 1
Cd onecd 1
Cd pocket 4
Bag onebag 15

As we see, each stock has some units. Now I want to know how many units do i have according to the amount field, For example:
We have 35 pens which is equal to 1 pocket and 1 dozen and 5 onepen because:

For pocket we have 1 pocket because (each pocket includes 24 pen)
35/24=1
35%24=11
For dozen we have 1 dozen because (each dozen includes 6 pen)
11/6=1
11%6=5
For onepen we have 5 onepen because
5 onepen because we don't have any smaller unit

Now we have:
1 pocket
1 dozen
5 onepen

Same calculation for Cd and Bag...

I know to get the desired result a temporary variable should be used to store the result of the MOD and use the variable for the next row but how?

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
Hamreen Ahmad
  • 522
  • 5
  • 21
  • 3
    You can use the `LAG()` command to retrieve the value of a field in a previous record. [mysql-lag-function](https://www.mysqltutorial.org/mysql-window-functions/mysql-lag-function/) – Mostafa NZ Jul 13 '22 at 18:59
  • 1
    The manual explicitly says reading & assigning the same variable in the same select statement is undefined behaviour in MySQL, see the documentation re assignment & variables. [Why the order of evaluation for expressions involving user variables is undefined?](https://stackoverflow.com/a/44751302/3404097) See my comments (re an incorrect answer) at [MySQL - Define a variable within select and use it within the same select](https://stackoverflow.com/a/16715618/3404097). You must use a stored procedure or 8.0+ window functions. – philipxy Jul 13 '22 at 20:10
  • @MostafaNZ LAG() is not storing data for 3 rows, i have to store the mod to be checked in 3 rows. LAG() simply shows the previous records value. – Hamreen Ahmad Jul 15 '22 at 16:13
  • By using the second parameter (offset) you can do this. [lag-transact](https://learn.microsoft.com/en-us/sql/t-sql/functions/lag-transact-sql?view=sql-server-ver16) – Mostafa NZ Jul 15 '22 at 16:18
  • @philipxy Thanks, you were right assigning and using a variable in the same SELECT sometimes will give wrong result sometimes. However I want to know if I use functions for example something like this `SELECT @z:=function1(@z,5) from (SELECT @z:=20 FROM table1) t;` Is there any possibility of being wrong with that query? or that one will not go wrong – Hamreen Ahmad Jul 26 '22 at 22:02
  • ?? Regardless of `function1`, `@z:=function1(@z,5)` is "reading & assigning the same variable in the same select statement" so "undefined". And when you aren't abusing variables, the manual says what that is relevant re functions in queries? And other Q&A? Re both your comment question & your post goal? (Rhetorical questions.) "You must use a stored procedure or 8.0+ window functions." PS Please ask a new question in a new post--if you need to after research. (But of course your comment question can be expected to be a duplicate.) – philipxy Jul 26 '22 at 22:24
  • Please before considering posting: Pin down code issues via a [mre]. Read the manual/reference & google any error message & many clear, concise & precise phrasings of your question/problem/goal, with & without your particular names/strings/numbers, 'site:stackoverflow.com' & tags; read many answers. Reflect research in posts. SO/SE search is poor & literal & unusual, read the help. Google re googling/searching, including in Q&A at [meta] & [meta.se]. [How much research effort is expected of Stack Overflow users?](https://meta.stackoverflow.com/q/261592/3404097) [ask] [Help] – philipxy Jul 26 '22 at 22:24
  • @philipxy I still have problem however my English is not very well, but I have searched a lot, I have not found an equivalent query that so something like this with Window Function `SELECT @z:=@z*2 from (SELECT @z:=20 FROM table1) t;`. I tried to use LAG but the problem is that I cant use the result of the LAG in the current row for next row. Can you help me? I want to use the value of a column in the current row for the same column in the next row (not only for two records but for all the records) – Hamreen Ahmad Jul 27 '22 at 09:15
  • Post a new question about how to write a query that returns the result that you want. This post asked a different question--about a certain (impossible) way of writing that query. [What is the XY problem?](https://meta.stackexchange.com/q/66377/266284) Give a [mre]. Show what relevant parts you can do. Use enough words, sentences & references to parts of examples to clearly & fully say what you mean. When giving a business relation(ship)/association or table (base or query result), say what a row in it states about the business situation in terms of its column values. Good luck. – philipxy Jul 27 '22 at 21:00

2 Answers2

1

How to store a result of a row in a variable and use it in the next row in MySQL SELECT query?

A pattern for MySQL version 5.x:

SELECT .. , 
       {an expression which uses @variable with the value from previous row} AS calculated_column,
       .. ,
       @variable := {an expression for current row which will be used for next row processing} AS dummy_column,
       ..
FROM {source single table or subquery}
CROSS JOIN ( SELECT @variable := {initial variable value} ) AS init_variable
ORDER BY {ordering expression which provides rows uniqueness}

On MySQL 8+ use window function(s).

Akina
  • 39,301
  • 5
  • 14
  • 25
  • The manual explicitly says that assigning & using a user variable in the same select statement is undefined behaviour. See my comment/links on the question. – philipxy Jul 13 '22 at 20:10
  • @philipxy This is true. But this is a theory. When the data source is one table and definite ordering is applied, the variables evaluation matches the query text and rows ordering - this is a practice, and I have never seen the exclusion yet, even on recent versions. And, as I have read, on old, 5.x, versions, this matching is confirmed by the server source code. Moreover, the variable value inline assigning itself is not recommended in recent versions too, RM recommends to use SELECT INTO instead. – Akina Jul 14 '22 at 04:34
  • You have given neither a version nor justification in this answer. So this is no answer. – philipxy Jul 14 '22 at 04:57
  • @philipxy When I have said that I have read about then I mean that some specialist have investigated the source code and have found the fact which I have told above. And I believe that the server action cannot contradict its source code. – Akina Jul 14 '22 at 05:01
  • See my last comment. – philipxy Jul 14 '22 at 05:02
  • @philipxy *You have given neither a version nor justification in this answer.* Does my words "A pattern for MySQL **version 5.x**:" is not a version info / justification? – Akina Jul 14 '22 at 05:03
  • No it is a claim without justification. I'm done. – philipxy Jul 14 '22 at 05:03
  • @philipxy Well, maybe you're right. – Akina Jul 14 '22 at 05:04
0

First of all, your Stocks and StockUnits make no sense, or they are at least bad designed.

You show that you store the id of each stock-row in multiple unit-rows, but it really should be the other way around.

How Stocks table should be:

id name qty unit_id
1 Pen 5 1
2 Pen 1 2
3 Pen 1 3
...

How StockUnits table should be:

id name include
1 onepen 1
2 dozen 6
3 pocket 24
...

Example

Once you fix the design mistake, all you would need to do is join to get unit's name, for example in Laravel do something like:

$stockTable = Stock::with('unit')->all();

echo 'stock | unit | qty';
foreach ($stockTable as $item) {
    echo $item->name . ' | ' . $item->unit->name . ' | ' . $item->qty;
}

To get output:

name unit qty
Pen onepen 5
Pen dozen 1
Pen packet 1
...
Top-Master
  • 7,611
  • 5
  • 39
  • 71