SQL WHERE condition for the most recent row - mysql

I know this should be super easy, but I just can't get my head around it.
I have a table with values like this:
+----+-------+
| ID | VALUE |
+----+-------+
| 1 | 100 |
| 2 | 200 |
| 3 | 100 |
| 4 | 300 |
+----+-------+
I want to check if the most recent row (id 4) have the value 100.
I can't use LIMIT 1 or anything, and I'm sure I should use MAX() somehow, but I don't know where to start.
Thanks

Try this:
SELECT * -- (or others fields you need)
FROM YOUR_TABLE AS A
WHERE A.ID = (SELECT MAX(B.ID)
FROM YOUR_TABLE AS B) AND A.VALUE = 100 --(OR ELSE)

Related

MySQL: Get minimal set of entries where sum(value) is bigger then given number

I've got a new/special problem where I wasnt able to get a good solution, maybe someone has an idea?
Table as follows:
| id | value |
---------------
| … | … |
| 11 | 500 |
| 12 | 300 |
| 13 | 200 |
| 14 | 400 |
| 15 | 300 |
---------------
Now I need to select (and then delete/update) these entries until my given value (1250) is reached, so after "the magic" I need the table as follows:
| id | value |
---------------
| … | … |
| 11 | 450 |
---------------
Is there any good possibility to do it (performance matters)? (that select query, the other two should be much easier then)
I've found some solutions with subselect (w/o limit…) and "where sum() <= 1250" but they dont work, because they only select the ids 15,14,13&12, not 11. i need something like "give minimal set of entries where sum(value) is bigger then 1250 order by id desc"
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,value INT NOT NULL
);
INSERT INTO my_table VALUES
(10,700),
(11,500),
(12,300),
(13,200),
(14,400),
(15,300);
For simplicity, the following query assumes that ids are contiguous, but it can be easily extended to situations where they are not.
SELECT a.id
, LEAST(a.value,a.value-i) value
FROM my_table a
JOIN
( SELECT *
, #i:=#i-value i
FROM my_table
, ( SELECT #i:=1250) vars
ORDER
BY id DESC
) b
ON b.id = a.id + 1
AND a.value - i >= 0;
+----+-------+
| id | value |
+----+-------+
| 10 | 700 |
| 11 | 450 |
+----+-------+

How does this matrix multiply work in SQL?

Full disclosure, I'm a noob at SQL
Given two sparce matrices A and B, defined as:
A(row_number, column_number, value) and B(row_number, column_number, value)
I don't understand how this query represents the multiplication of the two matrices:
SELECT A.row_number, B.column_number, SUM(A.value * B.value)
FROM A, B
WHERE A.column_number = B.row_number
GROUP BY A.row_number, B.column_number
My confusion lies in the SUM syntax and the GROUP BY / SELECT syntax
So for my GROUP BY / SELECT confusion, I don't understand why the expressions
A.row_number and B.column_number are necessary after the SELECT statement
Why do we have to specify that when we're already using SELECT and WHERE ? To me that seems like we're saying we want to SELECT using those expressions (A.row_number and B.column_number) even though we're given back a table from WHERE already. Would it not make more sense to just say SELECT * ? I'm assuming that GROUP BY just requires you to type out the expressions it uses in the SELECT statement, but I don't know for sure.
For the SUM, I just want to clarify, the SUM is only using the A.value and the B.value from whatever is returned by the WHERE correct? Otherwise, you would be multiplying all A.value with all B.value.
Clarifying either of these would be immensely helpful. Thank you!
create table A
( column_number int,
row_number int,
value int
);
create table B
( column_number int,
row_number int,
value int
);
insert A (column_number,row_number,value) values (1,1,1),(1,2,2),(2,1,3),(2,2,4);
insert B (column_number,row_number,value) values (1,1,10),(1,2,20),(2,1,30),(2,2,40);
Data with your old style (non explicit) join without aggregage or group by:
SELECT A.row_number as Ar, B.column_number as Bc,
A.value as Av,B.value as Bv,A.value*B.value as product
FROM A, B
WHERE A.column_number = B.row_number
+------+------+------+------+---------+
| Ar | Bc | Av | Bv | product |
+------+------+------+------+---------+
| 1 | 1 | 1 | 10 | 10 |
| 2 | 1 | 2 | 10 | 20 |
| 1 | 1 | 3 | 20 | 60 |
| 2 | 1 | 4 | 20 | 80 |
| 1 | 2 | 1 | 30 | 30 |
| 2 | 2 | 2 | 30 | 60 |
| 1 | 2 | 3 | 40 | 120 |
| 2 | 2 | 4 | 40 | 160 |
+------+------+------+------+---------+
Seeing the above, the below gets a little more clarity:
SELECT A.row_number, B.column_number,sum(A.value * B.value) as theSum
FROM A, B
WHERE A.column_number = B.row_number
GROUP BY A.row_number, B.column_number
+------------+---------------+--------+
| row_number | column_number | theSum |
+------------+---------------+--------+
| 1 | 1 | 70 |
| 1 | 2 | 150 |
| 2 | 1 | 100 |
| 2 | 2 | 220 |
+------------+---------------+--------+
Giving table name after SELECT will identify which table to refer to. Mainly useful in the case where both tables have same column names.
GROUP BY will aggregate the data and display one record per grouped-by value. That is, in your case, you'll end up with only one record per row-column combination.
By definition multiplication of two matrices A(n,m) and B(m,p) produces a matrix C(n,p).
So the SQL for multiplication should return same data structure as was used for storage of A and B, which is three columns:
row_number
column_number
value
, with one value per (row, column) combination.
This is why you need first two in the group by clause.
WHERE clause is independent from SELECT. First is responsible for getting the right records, second for getting the right columns.

add a temporary column in SQL, where the values depend from another column

I have this table:
ID | name | result |
--------------------
1 | A | 1 |
--------------------
2 | B | 2 |
--------------------
3 | C | 1 |
--------------------
1 | A | 2 |
--------------------
4 | E | 2 |
--------------------
I want to add a new temporary column next to |result|, and where result=1 the value should be 100, and where result=2 the value should be 80 so it should look like this:
ID | name | result | NewColumn|
-------------------------------
1 | A | 1 | 100 |
-------------------------------
2 | B | 2 | 80 |
-------------------------------
3 | C | 1 | 100 |
-------------------------------
1 | A | 2 | 80 |
-------------------------------
4 | E | 2 | 80 |
-------------------------------
How can I query this in SQL ?
Use a CASE expression in your SELECT's column list - something like this:
SELECT
ID,
name,
result,
CASE
WHEN result = 1 THEN 100
WHEN result = 2 THEN 80
ELSE NULL
END AS NewColumn
FROM YourTable
Add additional WHEN expressions or alter the ELSE expression as needed.
You could add a case statement to your query:
SELECT id, name, result, CASE result WHEN 1 THEN 100 WHEN 2 THEN 80 ELSE NULL END
from my_table
SELECT ID
,name
,result
,NewColumn = CASE WHEN result = 1 THEN 100 WHEN result = 2 THEN 80 END
FROM Table1
As the answers given above are also correct. But I will say that if you have a predefined relation or logic between the existing column and the new column then you can also achieve that without the CASE. Writing CASE for all the possible values would not be possible nor efficient.
For your existing data. I can use it something like this
SELECT ID, name, result, (20*(6-result)) as NewColumn
FROM YourTable
Here I am assuming that 1=>100, 2=>80, 3=>60, 4=>40, 5=>20.
of course this only for understanding purpose. You can create your own expression depending on the actual data.
You would use IF Statement in Mysql
SELECT col1,col2,col3, IF(col3=1,'100', IF(col3=2,80,''))
FROM your_table

MySQL Combining Tables Specific Order

This seems to be a convoluted problem, but I'll try my best to articulate the idea and illustrate a scenario. Essentially I have two tables that need to be combined and returned as the result set for a single query. One table needs to be merged into the other in a specific order.
Say table one is called Articles and table two is called Features. Both tables have an ID field with unique numbers. Articles has a date field which will be used to initially sort its records in descending order. The Features table has a Delta field which be used initially to sort its records. Some of the records in the Features table are placeholders and are not meant to be included in the final set. Their only purpose is to affect the sort order. Each record has a unique value in the Delta field, from 1 - X which will be used to sort these records. Another field called Skip has a value of 1 if it should be eliminated when merging the two tables together. Again, the only purpose to the skipped records is to take up space during the initial sort on the Features table. Even though they are unnecessary, they exist and can't be deleted.
The tricky part is that when the results from both tables are merged, any non-skipped records from the Features table need to be inserted into the results from the Articles table in the exact order they appears in the Features table.
So lets say I have 6 records in the Features table, A - F and the order field ranges from 1 - 6. Records A,B,D,E all have a value of 1 in the Skip field. That means I'm only interested in records C and F both of which need to be inserted into the final record set in positions 3 and 6 respectively.
The records may look something like this for the Articles table:
+----+------------+
| id | date |
+----+------------+
| 1 | 9999999999 |
+----+------------+
| 2 | 9999999998 |
+----+------------+
| 3 | 9999999997 |
+----+------------+
| 4 | 9999999996 |
+----+------------+
| 5 | 9999999995 |
+----+------------+
| 6 | 9999999994 |
+----+------------+
| 7 | 9999999993 |
+----+------------+
| 8 | 9999999992 |
+----+------------+
| 9 | 9999999991 |
+----+------------+
| 10 | 9999999990 |
+----+------------+
The Features table may look something like this:
+----+------+-------+------+
| id | name | delta | skip |
+----+------+-------+------+
| 11 | A | 1 | 1 |
+----+------+-------+------+
| 12 | B | 2 | 1 |
+----+------+-------+------+
| 13 | C | 3 | 0 |
+----+------+-------+------+
| 14 | D | 4 | 1 |
+----+------+-------+------+
| 15 | E | 5 | 1 |
+----+------+-------+------+
| 16 | F | 6 | 0 |
+----+------+-------+------+
The results would look something like this (not including any additional fields that might be needed to achieve my goal):
+----+
| id |
+----+
| 1 |
+----+
| 2 |
+----+
| 13 | (record from the Features table in the third position)
+----+
| 3 |
+----+
| 4 |
+----+
| 16 | (record from the Features table in the sixth position)
+----+
| 5 |
+----+
| 6 |
+----+
| 7 |
+----+
| 8 |
+----+
| 9 |
+----+
| 10 |
+----+
Hope my explanation makes sense. Any ideas?
Thanks,
Howie
I assume that there is a mistake in your example - record id=16 is sixth row in Features table, so should be after id=5 in results, not before.
Try the blelow query. Here is SQLFiddle.
select id from (
select `date`, null delta, id
from Articles
union all
select a.`date`, f.delta, f.id
from (
select (#x:=#x+1) rn, a.*
from Articles a, (select #x:=0) z
order by a.`date` desc
) a
join (
select (#y:=#y+1) rn, f.id, f.delta, f.skip
from Features f, (select #y:=0) z
order by f.delta
) f
on a.rn = f.rn
where f.skip <> 1
order by `date` desc, isnull( delta ), delta
) merge
Looks like this example in SQL Fiddle did it for me.
SELECT id, sort_order FROM (
SELECT `date`, NULL delta, id, (#a_count:=#a_count+1) sort_order
FROM Articles a_main, (SELECT #a_count:=-1) z
UNION ALL
SELECT a.`date`, f.delta, f.id, f.weighted_rn
FROM (
SELECT (#x:=#x+1) rn, a.*
FROM Articles a, (SELECT #x:=-1) z
ORDER BY a.`date` DESC
) a
JOIN (
SELECT (#y:=#y+1) rn, TRUNCATE((f.delta - #y - (1/#y)),2) AS weighted_rn, f.id, f.delta, f.skip
FROM Features f, (SELECT #y:=-1) z
WHERE f.skip <> 1
ORDER BY f.delta
) f
ON a.rn = f.rn
ORDER BY sort_order
) merge
Thanks to Kordirko for the framework.

Expanding a mySQL table using only mySQL

Let's say I have a mySQL table whose structure is like this:
mysql> select * from things_with_stuff;
+----+---------+----------+
| id | counter | quantity |
+----+---------+----------+
| 1 | 101 | 1 |
| 2 | 102 | 2 |
| 3 | 103 | 3 |
+----+---------+----------+
My goal is to "expand" the table so I end up with something like:
mysql> select * from stuff;
+----+---------+
| id | counter |
+----+---------+
| 1 | 101 |
| 2 | 102 |
| 3 | 102 |
| 4 | 103 |
| 5 | 103 |
| 6 | 103 |
+----+---------+
And I want to do this "expansion" using only mysql. Note that I end up with a row per quantity and per counter. Any suggestions? A stored procedure is not an option here (I know they offer while loops).
Thanks!
The following will do the trick as long as some_large_table has a length greater than or equal to the largest quantity in things_with_stuff. For example, let some_large_table be a big fact table in a data warehouse.
SELECT #kn:=#kn+1 AS id, counter
FROM (SELECT #kn:=0) k, things_with_stuff ts
INNER JOIN (
SELECT #rn:=#rn+1 AS num
FROM (SELECT #rn:=0) t, some_large_table
) nums ON num <= ts.quantity;
Assuming there is a maximum value for quantity, you could do:
INSERT INTO things SELECT counter FROM things_with_stuff WHERE quantity > 0;
INSERT INTO things SELECT counter FROM things_with_stuff WHERE quantity > 1;
INSERT INTO things SELECT counter FROM things_with_stuff WHERE quantity > 2;
--... and so on until the max.
It's a bit of a hack but it should do the job.
If the ordering is important you could do a clean up afterwards.
I have sometimes in databases a table named num (number) with a single column i, filled with all integers from 1 to 1000000. It's not hard to make such a table and populate it.
Then you could use this if stuff.id is auto incremented:
INSERT INTO stuff
( counter )
SELECT ts.counter
FROM things_with_stuff AS ts
JOIN num
ON num.i <= ts.quantity