In MySQL, I have two tables:
CATEGORY
----------------------------------------------
| category_name | category_code |
----------------------------------------------
| Suit | SU |
| Western | WE |
----------------------------------------------
PRODUCT
---------------------------------------------
| name | Category | code |
---------------------------------------------
| xyz1 | Suit | |
| abc1 | Suit | |
| abc2 | Western | |
---------------------------------------------
I want to update code in PRODUCT, so that after updation it is will:
PRODUCT
---------------------------------------------
| name | Category | code |
---------------------------------------------
| xyz1 | Suit | SU/0001 |
| abc1 | Suit | SU/0002 |
| abc2 | Western | WE/0001 |
---------------------------------------------
thanks in advance
Honestly, it looks like you need restructure your database. Each table should have an auto-incrementing "id" field. This would allow the "Category" field to reference an id instead of a duplicate of the name (in case you EVER decide to change the spelling or name of that category). Even down to your naming - if your field is IN the category table, it doesn't seem necessary to have "category_" before the "code" field name...etc
Beyond that, you're probably talking about a PHP script (or something similar) - this would allow you to repeat through each item and keep track of how many Suit codes you've added so you can increment your "code" field (I assume that's what the 0001 0002 is doing.
Off the top of my head, it'd be something like this (I'm sure it could be more streamlined/better - but hopefully this gives an idea of a way you could do it:
$numSU = 0;
$numWE = 0;
$products = mysql_fetch_array(mysql_query("SELECT * FROM product"));
foreach($products as $p) {
$codeQuery = mysql_query("SELECT category_code FROM category WHERE category_name='".$p['Category']."'");
$code = mysql_result($codeQuery,0,'category_code');
if($code == "SU") {
$numSU++;
$numItems = $numSU;
} else if($code == "WE") {
$numWE++;
$numItems = $numWE;
}
$update = mysql_query("UPDATE product SET code='".$code."/".$numItems."'");
}
Related
Note. Also posted on Database Administrators
I have one table that records all sales and fourteen supplemental tables which contain extra information about a sale. The fourteen supplemental tables are for all intents and purposes the same. They were created long ago when the initial developer thought there would be more differences but actually now that the project has matured they are more similar than they are different. They are different however, and as such I need to keep them separate.
Current structure
Sales table
| id | customer_id | customer_ref | ... |
|---------|-------------|--------------------------------------|-----|
| 1237567 | 354 | a6143f8c-b679-47be-9bc0-52457842913c | ... |
| 1237568 | 867 | ref89b72 | ... |
| ... | ... | ... | ... |
Supplemental table 1 Class: App\SuppOne
| id | customer_id | customer_ref | ... |
|------|-------------|--------------------------------------|-----|
| 2857 | 10372 | 2016-07-01-ab5d09cc37ca | ... |
| 2858 | 354 | a6143f8c-b679-47be-9bc0-52457842913c | ... |
| ... | ... | ... | ... |
Supplemental table 2 Class: App\SuppTwo
| id | customer_id | customer_ref | ... |
|-------|-------------|--------------|-----|
| 90488 | 867 | ref89b72 | ... |
| 90489 | 1024 | 0000080992 | ... |
| ... | ... | ... | ... |
There are no foreign keys on the tables to join the sales table to the supplemental tables but there is a 'customer_id' and 'customer_reference' which are unique to both the sales tables and also the supplemental tables but they are not consistent. This is what is currently used to join the two as-and-when I need to get more information about a given sale.
I'm using Laravel 5.1 and a MySQL database and I'd like to add two fields to the sales table; supplemental_id and supplemental_type in order to quickly and efficiently create a polymorphic relation.
Desired structure
Sales table
| id | supplemental_id | supplemental_type | customer_id | customer_ref | ... |
|---------|-----------------|-------------------|-------------|--------------------------------------|-----|
| 1237567 | 2858 | App\SuppOne | 354 | a6143f8c-b679-47be-9bc0-52457842913c | ... |
| 1237568 | 90488 | App\SuppTwo | 867 | ref89b72 | ... |
| ... | ... | ... | ... | ... | ... |
I need to add these two fields to each of the sales records but I am unsure how to do this with raw SQL as I expect it would be much quicker than if done in a migration. I'd like to know how (if possible) in SQL, do I deal with the mapping from table_name to App\ClassName. There are about 1.5m records in the sales table and looping over them all will not take an insignificant amount of time.
something between the lines of.
It can potentially override the data, for particular sale record (ie. SuppFourteen overrides SuppOne data), but that's how you presented it in your question.
$fourteen_tables = [
'supplemental_table_1' => App\SuppOne::class,
// ...
];
foreach ($fourteen_tables as $table => $class) {
DB::table('sales_table')
->join($table, function ($join) use ($table) {
$join->on($table.'.customer_id', '=', 'sales_table.customer_id')
->on($table.'.customer_ref', '=', 'sales_table.customer_ref');
})
->update([
'sales_table.supplemental_id' => DB::raw($table.'.id'),
'sales_table.supplemental_type' => $class,
]);
}
I'm currently trying to update an existing database (removing duplicates).
You can see the structure as follows :
I have a database on which specific entries are marked as "Main". These entries need to be updated with data from duplicate records, only having the same name.
(Updated table to reflect my question better)
It would look like this:
+----+------+-----------------+--------------+---------+
| ID | Name | Field-To-Update | Duplication | Source |
+----+------+-----------------+--------------+---------+
| . | A | xxx | Main | 1 |
| . | A | yyy | "" | 2 |
| . | A | zzz | "" | 3 |
| . | B | foo | "" | 1 |
| . | B | bar | Main | 2 |
+----+------+-----------------+--------------+---------+
Should result in
+----+------+-----------------+--------------+-----------------------------------------------+
| ID | Name | Field-To-Update | Duplication | Source |
+----+------+-----------------+--------------+-----------------------------------------------+
| . | A | yyy | Main | 1 |
| . | A | yyy | "" | 2 |
| . | A | zzz | "" | 3 (should be updated from a specific source) |
| . | B | bar | "" | 1 |
| . | B | bar | Main | 2 (should be updated from a specific source) |
+----+------+-----------------+--------------+-----------------------------------------------+
Do any of you have an idea how to tackle this? I've tried with multiple queries for a couple of days now without any success.
you could use a update with join
update t
set t.field_to_update = x.field_to_update
from your_table t
inner join ( select name, field_to_update
from your_table
where Duplication <> 'Main') x
) on t.name = x.name
where t.Duplication = 'Main'
Bizarre requirement. You say you are updating to remove duplicates, however, it looks to me like you are creating duplicates.
There are only 2 records for each Name? Try:
UPDATE Table INNER JOIN
(SELECT Name, [Field-To-Update]
FROM Table
WHERE Duplication Is Null) AS Query1 ON
Table.Name = Query1.Name SET Table.[Field-To-Update] = [Query1]![Field-To-Update] WHERE Duplication = "Main";
Name is a reserved word in Access. Should not use reserved words as name for anything.
Darn! Did not see #scaisEdge answer before posting.
I tried the <> "Main" criteria and it did not work which was surprising - no records returned. So I switched to the Is Null parameter.
If you want to pull value from the maximum Source for each Name, then need a query that does that. Review http://allenbrowne.com/subquery-01.html#TopN. Then use that query in the above example as Query1.
I've looked a bunch of answers to this question here on SO and elsewhere but all I can track down is cases where people just want to find the highest id, the max dateCreated or the latest db entry but what I want to do is retrieve the latest object created that also matches another criteria. My domain class has the following properties: id, number, company, type, dateCreated and content. The company property can only be set to 'OYG' or 'BAW' and the number property is an auto incrementing int. What I want to do is retrieve the record with the highest number that also has its company property set to 'OYG' or 'BAW`.
So here's an example:
+----------------------------------------------------------+
| id | number | company | type | dateCreated | content |
+----------------------------------------------------------+
| 1 | 0 | OYG | TsAndCs | 15/09/2016 | stuff |
| 2 | 0 | BAW | TsAndCs | 15/09/2016 | stuff |
| 3 | 1 | OYG | TsAndCs | 16/09/2016 | stuff |
| 4 | 2 | OYG | TsAndCs | 17/09/2016 | stuff |
| 5 | 1 | BAW | TsAndCs | 16/09/2016 | stuff |
+----------------------------------------------------------+
I want to say def doc = Document.findByHighestNumberAndCompany('OYG') then it should bring back the object with id 4. def doc = Document.findByHighestNumberAndCompany('BAW') should bring back id 5's object, etc.
Any help would be appreciated. Thanks!
Despite Joshua Moore gave you a good solution, there is another simplier in one line.
MyDomain.findAllByCompany(company, [sort: 'number', order: 'desc', limit: 1])?.first()
Should be easy enough if you order by the number in descending order, and limit your results to one. So perhaps something like this?
String companyName = 'OYG'
def results = MyDomain.createCriteria().list() {
eq("company", companyName)
maxResults(1)
order("number", "desc")
}
println results[0].id // will print 4
Using this approach you could create a named query so you can pass the company name as a parameter.
I added a new column in one of my database tables. I'd like to try to populate that column for previous records. New records will be validated through forms. Here is an example.
| Quantity | Description | Price | Amount | Type |
----------------------------------------------------------
| 3 | Storage for Pallets | 3.99 | 11.97 | NULL |
| 3 | Handling for Pallets| 3.99 | 11.97 | NULL |
| 3 | Misc expense | 3.99 | 11.97 | NULL |
----------------------------------------------------------
I'd like to replace those null values based off of keywords in the description. For example the updated table would look like the following.
| Quantity | Description | Price | Amount | Type |
--------------------------------------------------------------
| 3 | Storage for Pallets | 3.99 | 11.97 | Storage |
| 3 | Handling for Pallets| 3.99 | 11.97 | Handling |
| 3 | Misc expense | 3.99 | 11.97 | Misc |
--------------------------------------------------------------
Any ideas on an update statement that will accomplish this?
Because there is no primary key you have put the values into the where clause for all columns' values. Or at least enough so that there is no chance of the update hitting 2+ rows, based on your knowledge of the data.
Here is the first update as an example:
update tbl
set "Type" = 'Storage'
where "Quantity" = 3
and "Description" = 'Storage for Pallets'
and "Price" = 3.99
and "Amount" = 11.97;
Fiddle:
http://sqlfiddle.com/#!12/9fa64/1/0
If there were a primary key, your WHERE clause would be a lot simpler:
where pk_id_field = x
(Because you could rest assured knowing you're about to update the exact row needed, and that no other rows have that value)
It was simpler than I thought
UPDATE
invoice_line_items
SET
line_item_type = "Storage"
WHERE
description like "%storage%";
.....and so on
Actually: If you always want the description's first word for the type, you can go with
UPDATE Invoice_Line_Items
SET line_item_type = SUBSTRING_INDEX(description, ' ', 1);
See SQL Fiddle. You could, of course, add a WHERE clause, if it is not just as straightforward for the whole table… And you are not limited to the first word either…
I'm working with a CMS system where I cannot control database column names. And I've got two related tables:
Table: content
+------------+----------+----------+----------+----------+
| content_id | column_1 | column_2 | column_3 | column_4 |
+------------+----------+----------+----------+----------+
| 1 | stuff | junk | text | info |
| 2 | trash | blah | what | bio |
+------------+----------+----------+----------+----------+
Table: column_names
+------------+-------------+
| column_id | column_name |
+------------+-------------+
| 1 | good_text |
| 2 | bad_text |
| 3 | blue_text |
| 4 | red_text |
+------------+-------------+
What I'd like to do here is select from the first table, but select the columns AS the column_name from the second table. So my result would look like:
+------------+-----------+----------+-----------+----------+
| content_id | good_text | bad_text | blue_text | red_text |
+------------+-----------+----------+-----------+----------+
| 1 | stuff | junk | text | info |
| 2 | trash | blah | what | bio |
+------------+-----------+----------+-----------+----------+
There is no way to do this, but as long as your columns won't change too often, a VIEW on that table with hard-coded aliases could be sufficient.
To my knowledge you can't use subselects as the target of an AS in SQL. If I were you, I'd load the data from column_names into an array (I'd also cache it in an in-memory DB since it isn't going to change all that often), then use that array to build my SQL.
A very rough example (in PHP):
$column_relations = array();
$sql = "SELECT * FROM column_names;";
$res = mysql_query($sql);
while ($row = mysql_fetch_assoc($res))
{
$column_relations[$row['column_name']] = 'column_' . $row['column_id'];
}
$sql = sprintf("SELECT content_id, '%s' AS good_text, '%s' AS bad_text, '%s' AS blue_text, '%s' AS red_text FROM content;", $column_relations['good_text'], $column_relations['bad_text'], $column_relations['blue_text'], $column_relations['red_text']);
SELECT
cn. column_id id,
MAX(IF(content_id=1,column_1,null)) as good_text,
MAX(IF(content_id=2,column_2,null)) as bad_text,
MAX(IF(content_id=3,column_3,null)) as blue_text,
MAX(IF(content_id=4,column_4,null)) as red_text
FROM content ct
INNER JOIN column_names cn ON (cn. column_id = ct.content_id)
GROUP BY cn. column_id
Sorry, it should be LEFT JOIN, not INNER.
You cannot have a dynamic number of columns, so this solution works only if you know in advance how many
groups you might have.