Sql moving values from one column to two different columns - mysql

My problem is as follows - in the database I have a Products table with a size column. However, I have now created two new columns x_size and y_size and I wanted to move the values from the size column to these 2 columns. For example, in the database I have a record, where the size column value is 100x200, now I want to transfer '100' to the new x_size column and '200' to the y_size column, and so for each of the records in this table.
I was trying with :
UPDATE `post` SET `x_size `=`size`
UPDATE `post` SET `y_size `=`size`
But this updates the value of the entire size column, not just part of it. I will be grateful for your help

If you have multiple records that you want to transfer from size column, you could do fetch all the records from your table, and then split your size values using PHP explode() function. Since you tagged Laravel, here's the simple Laravel solution:
$products = Products::get();
foreach ($products as $product){
$size = explode('x', $product->size);
$product->x_size = $size[0]; //First element from exploded array
$product->y_size = $size[1]; //Second element from exploded array
$product->save();
}
Tinker output:
>>> $size = '100x200';
=> "100x200"
>>> $exlpodedArray = explode('x', $size);
=> [
"100",
"200",
]
>>> $x_size = $exlpodedArray[0];
=> "100"
>>> $y_size = $exlpodedArray[1];
=> "200"

You can use substring_index():
UPDATE post
SET x_size = substring_index(size, 'x', 1),
y_size = substring_index(size, 'x', -1)

Related

Update and insert from qtableWidget into MYSQL database more efficiently

I'm building a desktop app with PyQt5 to connect with, load data from, insert data into and update a MySQL database. What I came up with to update the database and insert data into the database works. But I feel there should be a much faster way to do it in terms of computation speed. If anyone could help that would be really helpful. What I have as of now for updating the database is this -
def log_change(self, item):
self.changed_items.append([item.row(),item.column()])
# I connect this function to the item changed signal to log any cells which have been changed
def update_db(self):
# Creating an empty list to remove the duplicated cells from the initial list
self.changed_items_load= []
[self.changed_items_load.append(x) for x in self.changed_items if x not in self.changed_items_load]
# loop through the changed_items list and remove cells with no values in them
for db_wa in self.changed_items_load:
if self.tableWidget.item(db_wa[0],db_wa[1]).text() == "":
self.changed_items_load.remove(db_wa)
try:
mycursor = mydb.cursor()
# loop through the list and update the database cell by cell
for ecr in self.changed_items_load:
command = ("update table1 set `{col_name}` = %s where id=%s;")
# table widget column name matches db table column name
data = (str(self.tableWidget.item(ecr[0],ecr[1]).text()),int(self.tableWidget.item(ecr[0],0).text()))
mycursor.execute(command.format(col_name = self.col_names[ecr[1]]),data)
# self.col_names is a list of the tableWidget columns
mydb.commit()
mycursor.close()
except OperationalError:
Msgbox = QMessageBox()
Msgbox.setText("Error! Connection to database lost!")
Msgbox.exec()
except NameError:
Msgbox = QMessageBox()
Msgbox.setText("Error! Connect to database!")
Msgbox.exec()
For inserting data and new rows into the db I was able to find some info online about that. But I have been unable to insert multiple lines at once as well as insert varying column length for each row. Like if I want to insert only 2 columns at row 1, and then 3 columns at row 2... something like that.
def insert_db(self):
# creating a list of each column
self.a = [self.tableWidget.item(row,1).text() for row in range (self.tableWidget.rowCount()) if self.tableWidget.item(row,1) != None]
self.b = [self.tableWidget.item(row,2).text() for row in range (self.tableWidget.rowCount()) if self.tableWidget.item(row,2) != None]
self.c = [self.tableWidget.item(row,3).text() for row in range (self.tableWidget.rowCount()) if self.tableWidget.item(row,3) != None]
self.d = [self.tableWidget.item(row,4).text() for row in range (self.tableWidget.rowCount()) if self.tableWidget.item(row,4) != None]
try:
mycursor = mydb.cursor()
mycursor.execute("INSERT INTO table1(Name, Date, Quantity, Comments) VALUES ('%s', '%s', '%s', '%s')" %(''.join(self.a),
''.join(self.b),
''.join(self.c),
''.join(self.d)))
mydb.commit()
mycursor.close()
except OperationalError:
Msgbox = QMessageBox()
Msgbox.setText("Error! Connection to database lost!")
Msgbox.exec()
except NameError:
Msgbox = QMessageBox()
Msgbox.setText("Error! Connect to database!")
Msgbox.exec()
Help would be appreciated. Thanks.
Like if I want to insert only 2 columns at row 1, and then 3 columns at row 2
No. A given Database table has a specific number of columns. That is an integral part of the definition of a "table".
INSERT adds new rows to a table. It is possible to construct a single SQL statement that inserts multiple rows "all at once".
UPDATE modifies one or more rows of a table. The rows are indicated by some condition specified in the Update statement.
Constructing SQL with %s is risky -- it gets in trouble if there are quotes in the string being inserted.
(I hope these comments help you get to the next stage of understanding databases.)

Insert multiple values in MySQL with Python from an array

I am trying to insert data from my array into MySQL.
To my big surprise there were not many examples on how to do it if you perform a for-loop for your array, every example that I have found was from an already existing array list.
Thanks to Adrian below, we noticed that I need tuples for my list.
Updated code
connection = mysql.connector.connect(
host='localhost',
database='test',
user='root',
password='pass'
)
query = "INSERT INTO blue (created, published, publisher) VALUES (%s, %s, %s)"
array = []
# The idea here is to get all table rows in the page so you can group the values into rows that are going to be added to MySQL
tr = soup.find_all('tr')
for table_row in tr:
row_data = table_row.find_all('td')
insert_row = []
for data in row_data:
data = re.sub('<[^>]*>', '', str(data))
insert_row.append(data)
array.append(tuple(insert_row))
print(array)
cursor = connection.cursor()
cursor.executemany(query, array)
cursor.commit()
Getting close but at the moment I receive the following
IndexError: Tuple index out of range
mysql.connector.errors.ProgrammingError: Not enough parameters for the SQL statement
Thanks in advance!
I think you are mixing two ways of solving the problem...
One way is using the executemany method as described in the documentation
query = "INSERT INTO blues (created, published, publisher) VALUES (%s, %s, %s)"
array = []
# The idea here is to get all table rows in the page so you
# can group the values into rows that are going to be added to MySQL
tr = soup.find_all('tr')
for table_row in tr:
row_data = table_row.find_all('td')
insert_row = [None, None, None]
for idx in range(len(row_data)):
if row_data[idx] and idx < 3:
data = re.sub('<[^>]*>', '', str(row_data[idx]))
if data:
insert_row[idx] = data
array.append(tuple(insert_row))
cursor = connection.cursor()
cursor.executemany(query, array)
cursor.commit()
Another way is to build the query yourself...
query = "INSERT INTO blues (created, published, publisher) VALUES "
array = []
# The idea here is to get all table rows in the page so you can group the values into rows that are going to be added to MySQL
tr = soup.find_all('tr')
for table_row in tr:
row_data = table_row.find_all('td')
insert_row = []
for data in row_data:
data = re.sub('<[^>]*>', '', str(data))
insert_row.append(data)
array.append(tuple(insert_row))
values = []
for item in array:
row = [None, None, None]
for idx in range(len(item)):
row[idx] = item[idx]
values.append(str(tuple(row)))
query += ",".join(values)
cursor = connection.cursor()
cursor.execute(query)
cursor.commit()
Hope this helps...

Yii2 Update where the condition is an Array

This is the update code
$clients = OpClient::find(['id'])->where(['status'=>'Active'])->all();
foreach($clients as $client)
{
$array[] = $client['unit_id'];
$unit = OpUnit::find()->where(['id'=>$array]);
file_put_contents('test.txt',print_r($client['unit_id'],true));
$connection = Yii::$app->db;
$connection->createCommand()->update('op_unit', ['selected' => 'Yes'], 'id='.$array.'')->execute();
}
How should I type in the update query where the id is an array? It keep showing error Array to string conversion. Any advice will be apprecieated. Thanks
should be this way ..
$connection->createCommand()->update('user',
['selected' => 'Yes'],['id' => $array])->execute();
try the real sql code using
$myRawSql= $connection->createCommand()->update('user',
['selected' => 'Yes'],['id' => $array])>getRawSql();
var_dump($myRawSql);
For searching you can use the IN condition. i.e
->andWhere(['in', 'id', [1, 2, 3]])
// Query will be: WHERE id IN (1, 2, 3)
http://www.yiiframework.com/doc-2.0/guide-db-query-builder.html
in: operand 1 should be a column or DB expression. Operand 2 can be
either an array or a Query object. It will generate an IN condition.
If Operand 2 is an array, it will represent the range of the values
that the column or DB expression should be; If Operand 2 is a Query
object, a sub-query will be generated and used as the range of the
column or DB expression. For example, ['in', 'id', [1, 2, 3]] will
generate id IN (1, 2, 3). The method will properly quote the column
name and escape values in the range. The in operator also supports
composite columns. In this case, operand 1 should be an array of the
columns, while operand 2 should be an array of arrays or a Query
object representing the range of the columns.
So basically you need to pass your array to IN for search.
For update you can use same Where syntax in updateAll command i.e
// UPDATE customer SET status = 1 WHERE id IN (1, 2, 3)
http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#updating-multiple-rows
Customer::updateAll(['status' => Customer::STATUS_ACTIVE], ['in', 'id', [1, 2, 3]]);
Hope this helps. Thanks.
You can use updateAll query :
$update = OpUnit::updateAll(['selected' => 'Yes'],['id' => $array]);
It returns number of rows updated.
Refer : http://www.yiiframework.com/doc-2.0/yii-db-activerecord.html#updateAll()-detail

Ordering a queryset by occurrences

I have a django model:
class Field:
choice = models.CharField(choices=choices)
value = models.CharField(max_length=255)
In my database I have some cases where there are 3 "fields" with the same choice, and some cases where there is 1 field of that choice
How can I order the queryset so it returns, sorted by choice, but with all ones in a set of 3 at the start?
For example
[1,1,1,3,3,3,4,4,4,2,5] where 1,2,3,4,5 are possible choices?
This is the best I can do using django's ORM. Basically, just like in SQL, you have to construct a custom order_by statement. In our case, we'll place it in the SELECT and then order by it:
1) Get a list of choices sorted by frequency: [1, 3, 4, 2, 5]
freq_list = (
Field.objects.values_list('choice', flat=True)
.annotate(c=Count('id')).order_by('-c', 'choice')
)
2) Add indexes with enumerate: [(0,1), (1,3), (2,4), (3,2), (4,5)]
enum_list = list(enumerate(freq_list))
3) Create a list of cases: ['CASE', 'WHEN choice=1 THEN 0', ..., 'END']
case_list = ['CASE']
case_list += ["WHEN choice={1} THEN {0}".format(*tup) for tup in enum_list]
case_list += ['END']
4) Combine the case list into one string: 'CASE WHEN choice=1 THEN 0 ...'
case_statement = ' '.join(case_list)
5) Finally, use the case statement to select an extra field 'o' which will be corresponding order, then just order by this field
Field.objects.extra(select={'o': case_statement}).order_by('o')
To simplify all this, you can put the above code into a Model Manager:
class FieldManager(models.Manager):
def get_query_set(self):
freq_list = (
Field.objects.values_list('choice', flat=True)
.annotate(c=Count('id')).order_by('-c', 'choice')
)
enum_list = list(enumerate(freq_list))
case_list = ['CASE']
case_list += ["WHEN choice={1} THEN {0}".format(*tup) for tup in enum_list]
case_list += ['END']
case_statement = ' '.join(case_list)
ordered = Field.objects.extra(select={'o': case_statement}).order_by('o')
return ordered
class Field(models.Model):
...
freq_sorted = FieldManager()
Now you can query:
Field.freq_sorted.all()
Which will get you a Field QuerySet sorted by frequency of choices
You should make a function and detect which is repeated to select unique, then calling from mysql as a function over mysql

Inserting & removing rows in a MySQL database without multiple queries

Check this example before reading the question - http://www.sqlfiddle.com/#!2/fcf3e/8
The following data comes from a form, the user simply removed a product from a special offer.
Array(
'special_offer_id' => 1,
'product_ids' => Array(
0 => 1,
0 => 2
)
)
Originally I wanted to use this query...
REPLACE INTO `foo` VALUES (1, 1), (2, 1);
But this won't remove the product that the user removed - only update the others.
So I'm forced to perform 2 queries...
DELETE FROM `foo` WHERE `special_offer_id` = 1;
INSERT INTO `foo` VALUES (1, 1), (2, 1);
Is there a better way to do this without having to perform 2 queries?
Example: http://www.sqlfiddle.com/#!2/fcf3e/8
I don't think it is possible within MySQL to combine DML statements. I do know that Oracle and MSSQL have the merge function for this but I think MySQL doens't have this function but i'm not quite sure about that.
Looking at your fiddle and what the code actually does I've came up with a different approach. If you loop through your array of data which is present and put the output into 1 variable and use the delete to delete the rows which do not match.
Here's an example based on your sqlfiddle (note that the array is not valid as it is not named correctly in the fiddle)
// Declare var and fill with array result
$exists = '';
for ($c = 0; $c < count($array); c++)
{
if ($c == (count($array) -1))
{
$exists .= $array[$c]['product_ids'];
}
else
{
$exists .= $array[$c]['product_ids'].',';
}
}
Then instead of doing two queries, you can do it with one
DELETE FROM `foo` WHERE `special_offer_id` NOT IN ('.$exists.');