Updating column so that it contains the row position - php

This is the content table:
ContentID | CategoryID | Position | Other1 | Other2
===================================================
1 | 1 | NULL | abcd | efgh
2 | 1 | NULL | abcd | efgh
3 | 1 | NULL | abcd | efgh
4 | 2 | NULL | abcd | efgh
5 | 2 | NULL | abcd | efgh
6 | 2 | NULL | abcd | efgh
These are the queries I'll be running:
SELECT ContentID FROM content WHERE CategoryID = 1 ORDER BY Position
SELECT ContentID FROM content WHERE CategoryID = 2 ORDER BY Position
Now I want to implement move up, move down, move to top and move to bottom function for content. All I need to do is to populate the Position column with numbers:
ContentID | CategoryID | Position
=================================
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 1
5 | 2 | 2
6 | 2 | 3
Is it possible to achieve this via single query in MySQL? Something like:
UPDATE content
SET Position = <ROW_NUMBER>
WHERE CategoryID = 1
ORDER BY Position
UPDATE content
SET Position = <ROW_NUMBER>
WHERE CategoryID = 2
ORDER BY Position

This should work
update
content,
(
select
#row_number:=ifnull(#row_number, 0)+1 as new_position,
ContentID
from content
where CategoryID=1
order by position
) as table_position
set position=table_position.new_position
where table_position.ContentID=content.ContentID;
But I would prefer to apply this first, to unset user defined variable
set #row_number:=0;
Added by Mchl:
You can do that in one statement like this
update
content,
(
select
#row_number:=ifnull(#row_number, 0)+1 as new_position,
ContentID
from content
where CategoryID=1
order by position
) as table_position,
(
select #row_number:=0
) as rowNumberInit
set position=table_position.new_position
where table_position.ContentID=content.ContentID;

Here is the solution that worked for me (hope it helps someone):
-- The following query re-populates the "Position" column with sequential numbers so that:
-- a) sequence is reset to 1 for each "group"
-- b) sequence is based on row number relative to each group depending on how ORDER BY is specified
-- c) sequence does not disturb the original order but
-- c.a) fixes NULLs so that they are moved to top
-- c.b) fixes duplicate position values depending on how ORDER BY is specified
-- ContentID is the primary key
-- CategoryID is a foreign key
-- Position column contains relative position of a record
SET #current_group = NULL;
SET #current_count = NULL;
UPDATE
content
SET Position = CASE
WHEN #current_group = CategoryID THEN #current_count := #current_count + 1
WHEN #current_group := CategoryID THEN #current_count := 1
END
ORDER BY CategoryID, Position -- <Column 3>, <Column 4>, ...

I think it would be very tedious to run additional queries all the time when you do some operations on the table. I would create a trigger that fires every time you want to insert/update something in the table.
In your case, a BEFORE UPDATE and BEFORE INSERT trigger would be advisable. If you also want to keep it clean after the deletion of an etntry, add an AFTER DELETE trigger.

Initial:
UPDATE content as uc
SET Position = (
SELECT count(*)
FROM content as sc
WHERE sc.CategoryId = uc.CategoryId AND sc.Position is not null)
WHERE uc.Position is null
ORDER BY uc.ContentId
Before insert:
UPDATE content
SET Position = Position+1
WHERE Position >= newPos AND CategoryId = newCat

Related

Updating the table with new value by finding specific row

I have a table that I add information depending on the order number.
So when I enter information, I add some column names as numbers.
Then update the rows with new values.
My table takes 3 values everytime I insert value.
order number| total left | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9|
------------------------------------------------------------------------
11 | 100 | a | b | c | d | e | f | 0 | | |
------------------------------------------------------------------------
12 | 10 | x | y | z | 0 | | | s | d | f|
-------------------------------------------------------------------------
When I try to add new column, the value of the new rows in every other value becomes null or 0 depending on if it is int or varchar.
When I insert 3 values to order number 12, I want the last 0 in that row to be updated.
(In this case, 4-5-6 but I get 7-8-9 updated.)
So what is the best way for finding the last row which is 0
(in this case column 4 for order number 12 and insert the new values of s,d,f to the 4-5-6 instead of 7-8-9 ?
So maybe something like:
Loop through rows, find 0, insert 3 rows, break.
I take the last column:
$NewColumnNameKoliAdet=$LastColumnName+1;
$NewColumnNameMusteri=$LastColumnName+2;
$NewColumnNameTarih=$LastColumnName+3;
Then I add columns and update the table.
$Query="ALTER TABLE `koli_stok_hareketleri`
ADD `$NewColumnNameKoliAdet` INT(11) NOT NULL AFTER `$LastColumnName`,
ADD `$NewColumnNameMusteri` VARCHAR(100) NOT NULL AFTER `$NewColumnNameKoliAdet`,
ADD `$NewColumnNameTarih` VARCHAR(100) NOT NULL AFTER `$NewColumnNameMusteri`;";
$Query="UPDATE koli_stok_hareketleri SET kalan_koli=kalan_koli-
'$Uretilen_Koli',
`$NewColumnNameKoliAdet` = '$Uretilen_Koli',
`$NewColumnNameMusteri` = '$Musteri_ismifromrow',
`$NewColumnNameTarih` = '$Now'
WHERE koli_ismi ='$Koli_IsmifromRow' AND
koli_parti_no='$Parti_NofromRow'";
So the problem is it adds three value to each row automatically and but when I update, I need to update the order number 12 from 4th column not 7.

MySQL Select Multiple Row with column value

I have a table has columns tag_id and item_id,
---------------------
| tag_id | item_id |
---------------------
| 1 | 2 |
| 2 | 2 |
| 4 | 2 |
| 3 | 5 |
| 5 | 7 |
| 11 | 5 |
---------------------
For example, I want to return item_id = 2 if I input tag_id = 1,2,4
what is the query should look like?
I am using Codeigniter.
If you are looking for Msql query that returns only one cell value you can use the following:
SELECT DISTINCT item_id FROM tableName WHERE tag_id IN (1, 2, 4)
Try this code.Will help you
$this->db->select('item_id');
$this->db->from('tblNAME');
$where = "tag_id='1' OR tag_id='2' OR tag_id='2 ";
$this->db->where($where);
return $this->db->get()->result();
Try this:
select * from table where tag_id in (1,2,4)
Thank you all answers but unfortunately not suitable for the use. Because I want it return exactly the item id = 2 if tag id = 1,2,4.
If we using IN(1,2,4) it will return item ids that has tag id 1 or 2 or 4.
Finally I figure out the SQL query should be
Select *, COUNT(item_id) AS id_count
FROM TABLE_NAME
WHERE tag_id IN(1,2,4)
GROUP BY item_id HAVING id_count = 3
Therefore, express it in a general form, we simply replace the 3 by the size of the array of tag id.

Know last X field value

I have a database with this table
+------+---------------------+-------------+
| id | key | value |
+------+---------------------+-------------+
| 152 | incidencia_0_fecha | 20150306 |
| 158 | incidencia_1_fecha | 20150307 |
| 234 | incidencia_2_fecha | 20150309 |
| . | ...... | ........ |
| n | incidencia_N_fecha | date_value |
+------+---------------------+-------------+
And I want to know what is the last key (N its dinamic and i don't know his last value). In this table the last must be incidencia_2_fecha.
How can i do it?
Thanks
You can easily get the number in the string using two REPLACES.
SELECT MAX(
REPLACE(REPLACE(`key`, 'incidencia_', ''), '_fecha', '')
)
FROM mytable
If the values in the id column are strictly increasing, you can do this:
SELECT key FROM your_table WHERE id = (SELECT MAX(id) FROM your_table);
EDIT 1:
If the table is quite large, you should make sure that there's an index on the id column. Otherwise the query could take a long time to run.
EDIT 2:
Another option, if the value column contains the date at the time the record was inserted (and is indexed), would be to do the above query, but replace id with value, i.e.
SELECT key FROM your_table WHERE value = (SELECT MAX(value) FROM your_table);
First fetch record in desc
SELECT key from tbl_name ORDER BY id DESC LIMIT 0,1

Sql – Insert value in first empty cell of column and show ID

I have an sql statement that will insert a value to the first empty cell. And if I ran the php script again, then it inserts into the next null cell etc.
Problem: I also want to find out the ID of that row, and value of another column in that row. In the Mysql table below, I want a value inserted in the first ‘null’ of COLUMN A, and also know the id and value in COLUMN B corresponding to that (ie id=3 and COLUMN B= 11).
My_TABLE
+---------+--------------+-------------+
| ID | COLUMN A | COLUMN B |
+---------+--------------+-------------+
| 1 | 6 | 78 |
| 2 | 7 | 90 |
| 3 | NULL | 11 |
| 4 | NULL | 5 |
| 5 | NULL | 123 |
+---------+--------------+-------------+
The following sql statement in PHP script will make it possible to insert value to the first empty cell in COLUMN A:
UPDATE My_TABLE
SET COLUMN A = 83
WHERE COLUMN A IS NULL
LIMIT 1;
Result will be:
+----+----------+------------+
| ID | COLUMN A | COLUMN B |
+----+----------+------------+
| 1 | 6 | 78 |
| 2 | 7 | 90 |
| 3 | 83 | 11 |
| 4 | NULL | 5 |
| 5 | NULL | 123 |
+----+----------+------------+
I also want to have an sql script that will print within PHP (echo) the values of ID and COLUMN B values corresponding to the first COLUMN A null value (ie ID= 3; COLUMN B= 11).
fetch the row by condition in this case you will have ID and COLUMN B
select *
from My_TABLE
where COLUMN A IS NULL
order by id
limit 1
Update by ID the selected row:
update My_TABLE
set COLUMN A = :SOME_VALUE
where ID = :ID_FROM_FETCH
Not sure if this case will fit what you are questioning.
mysqli_insert_id
From this function I'm pretty sure you will able to write the script for what you need.
Note* If it fits what you need, please read the warning as I'm not
sure if it will deprecated from the latest PHP version. Kindly take
note.

Next and Previous MySQL row based on name

I have a table with details on personnel. I would like to create a Next/Previous link based on the individual's last name. Since personnel were not added in alphabetical order, selecting the next or previous row based on its ID does not work.
It is a hefty table - the pertinent fields are id, name_l, and name_f. I would like to order by name_l, the individuals' last name.
How would I go about accomplishing this task?
Thanks!
Edit
This will be used on a Personnel Details page, the result will generate links to the next/prev entry in the database (ordered by last name) based on the current row. For example, if I am viewing Joe Hammer, the Next link would link to Frank Ingram.
Final code
Thanks to Daniel, here is what I finally got to work:
First, I set an increment at 0: $i = 0. Then, while looping through records with a while loop, I increased this by 1 = $i++. I then made a link to the details page for that particular entry:
Details
On the Details page, I used the following SQL to select the next record:
$row = $_GET['row'];
$getNext = mysql_query("SELECT * FROM members ORDER BY name_l, id LIMIT ".$row.", 1");
$next = mysql_fetch_assoc($getNext);
$nextLink = $row + 1;
Finally, the link:
<?php echo $next['name_l'] . ", " . $next['name_f'];?>
First of all, make sure that your name_l column is indexed. Then you can simply use the ORDER BY and the LIMIT clauses as follows:
SELECT * FROM personnel ORDER BY name_l, id LIMIT 0, 1;
Simply increment the 0 value in the LIMIT clause to select the next record within the ordered set. Therefore use LIMIT 1, 1 to get the second record, LIMIT 2, 1 for the third, etc.
To create an index on name_l you can use the CREATE INDEX command:
CREATE INDEX ix_index_name ON personnel (name_l);
Test case:
CREATE TABLE personnel (
id int not null primary key,
name_l varchar(10),
name_f varchar(10)
);
CREATE INDEX ix_last_name_index ON personnel (name_l);
INSERT INTO personnel VALUES (1, 'Pacino', 'Al');
INSERT INTO personnel VALUES (2, 'Nicholson', 'Jack');
INSERT INTO personnel VALUES (3, 'De Niro', 'Robert');
INSERT INTO personnel VALUES (4, 'Newman', 'Paul');
INSERT INTO personnel VALUES (5, 'Duvall', 'Robert');
Results:
SELECT * FROM personnel ORDER BY name_l, id LIMIT 0, 1;
+----+---------+--------+
| id | name_l | name_f |
+----+---------+--------+
| 3 | De Niro | Robert |
+----+---------+--------+
1 row in set (0.00 sec)
SELECT * FROM personnel ORDER BY name_l, id LIMIT 1, 1;
+----+--------+--------+
| id | name_l | name_f |
+----+--------+--------+
| 5 | Duvall | Robert |
+----+--------+--------+
1 row in set (0.00 sec)
SELECT * FROM personnel ORDER BY name_l, id LIMIT 2, 1;
+----+--------+--------+
| id | name_l | name_f |
+----+--------+--------+
| 4 | Newman | Paul |
+----+--------+--------+
1 row in set (0.00 sec)
1st UPDATE: (Further to the comments below)
The above example is suitable mainly if you start by displaying the first record, and then you move sequentially to next, and maybe next again, and perhaps one back, etc. You could also easily move x steps forward and x steps backwards, but this does not appear to be required.
If you start from a random record however, it will be more difficult to adapt the query above to get the next and previous records.
If this is the case, then you can simply keep an index counter of where you currently stand. You start with $index = 0, and display the first record by using ... LIMIT $index, 1. Then you display the next by incrementing $index by 1, and you display the previous by decrementing $index by 1.
If on the other hand, you will be rendering the personnel list, and then the user will click on one record (at random), you could also make this work with some help from the applications-side (php). Let's say you render the following ordered list to the user:
+----+-----------+--------+
| id | name_l | name_f |
+----+-----------+--------+ // [Hidden info]
| 3 | De Niro | Robert | // Row 0
| 5 | Duvall | Robert | // Row 1
| 4 | Newman | Paul | // Row 2
| 2 | Nicholson | Jack | // Row 3
| 1 | Pacino | Al | // Row 4
+----+-----------+--------+
Now if the user clicks on Newman Paul, you would have to pass the row=2 parameter to the page that will display the details of this employee. The page that renders the details of the employee now knows that Newman Paul is the 3rd row (row=2). Therefore to get the previous and the next records you would simply change the x in LIMIT x, 1 by row - 1 for the previous record and row + 1 for the next:
-- Previous
SELECT * FROM personnel ORDER BY name_l, id LIMIT 1, 1;
+----+--------+--------+
| id | name_l | name_f |
+----+--------+--------+
| 5 | Duvall | Robert |
+----+--------+--------+
1 row in set (0.00 sec)
-- Next
SELECT * FROM personnel ORDER BY name_l, id LIMIT 3, 1;
+----+-----------+--------+
| id | name_l | name_f |
+----+-----------+--------+
| 2 | Nicholson | Jack |
+----+-----------+--------+
1 row in set (0.00 sec)
2nd UPDATE:
You can use the following MySQL-specific query to get the record number within the ordered list of any random employee, which then can be used to get the previous and next records. Note however that this is not very efficient, and may degrade performance if you have thousands of records.
Let's say you are in employee Nicholson Jack.
You could do the following query:
SELECT p.id, p.name_l, p.name_f, o.record_number
FROM personnel p
JOIN (
SELECT id,
#row := #row + 1 AS record_number
FROM personnel
JOIN (SELECT #row := -1) r
ORDER BY name_l, id
) o ON (o.id = p.id)
WHERE p.name_l = 'Nicholson' AND p.name_f = 'Jack';
Which returns this:
+----+-----------+--------+---------------+
| id | name_l | name_f | record_number |
+----+-----------+--------+---------------+
| 2 | Nicholson | Jack | 3 |
+----+-----------+--------+---------------+
1 row in set (0.00 sec)
Note that in the WHERE clause you could have used p.id = 2 if the id is known, instead of p.name_l = 'Nicholson' AND p.name_f = 'Jack'.
Now we can use the record_number field, which is 3 in this case, to get the previous and the next records, simply by using the original query from the top of this answer, and replacing LIMIT 2, 1 for the previous and LIMIT 4, 1 for the next. There you go:
The previous of Nicholson Jack:
SELECT * FROM personnel ORDER BY name_l, id LIMIT 2, 1;
+----+--------+--------+
| id | name_l | name_f |
+----+--------+--------+
| 4 | Newman | Paul |
+----+--------+--------+
1 row in set (0.00 sec)
The next from Nicholson Jack:
SELECT * FROM personnel ORDER BY name_l, id LIMIT 4, 1;
+----+--------+--------+
| id | name_l | name_f |
+----+--------+--------+
| 1 | Pacino | Al |
+----+--------+--------+
1 row in set (0.00 sec)
Try a better SQL SELECT statement:
SELECT * FROM tblPersonnel ORDER BY name_l ASC
Try this link for more info:
http://w3schools.com/sql/sql_orderby.asp

Categories