I have an ajax live table edit to change the price of my current product. What I want to do is insert the price before I change it and then insert the updated price. The reason being is because I want to show the change in the updated price. Example: current price is $54.00 and I change it to $57.00. I need to keep a log of price change throughout the day and show the price change of $3.00. How would I go about inserting the old price while the updated price gets inserted also. Thanks.
I suggest you make your price table like this
table price
-----------
id unsigned integer autoincrement primary key
article_id integer /*link to articletable*/
valid_from date
valid_until date
amount decimal(10,2) /*always use decimal for money*/
Then you can insert your new price using the following 4 queries.
/*hide changes from the rest of the world until we are done*/
START TRANSACTION
/*invalidate the latest existing price in the price table*/
UPDATE price
SET valid_until = DATESUB(CURDATE(),INTERVAL 1 DAY)
WHERE article_id = '100' ORDER BY valid_until DESC LIMIT 1
/*the order by selects the latest item, the limit does only 1 update*/
/*insert the new price*/
INSERT INTO PRICE (article_id, valid_from, valid_until, amount)
VALUES ('100', CURDATE(), DATEADD(CURDATE(),INTERVAL 100 YEAR), '99.95')
/*show changes to the rest of the world*/
COMMIT
You need the transaction or you risk the price table being out of sync. Set the tabletype to InnoDB on the price table.
Al your other tables can be MyISAM, just make sure the price table is InnoDB.
You can now select prices by using:
SELECT article.name
,price.amount as price_per_item
,purchase.qty as number_of_items
,price.amount * purchase.qty as amount
FROM purchase
INNER JOIN article ON (article.id = purchase.article_id)
INNER JOIN price ON (price.article_id = purchase.article_id)
AND (purchase.transactiondate BETWEEN price.valid_from and price.valid_until)
WHERE purchase.id = '458'
you can maintain to different fields for the two. Like old_value and new_value. At the end of the day you can tally the values and print the difference.
Related
My table columns are invoiceid (primary AI), invoiceno, purchaseorderno, userid. I figured I couldn't use invoiceid since for example: when a customer buys 2 products, the 2 invoiceid will be diff. So I decided to use invoiceno that whenever the user will click order and he bought for example 2 products, they will have the same invoiceno. I have this code below:
$invoice = 0000000;
$invoiceno = $invoice + 1;
$sqlString1 = "INSERT INTO invoice
(invoiceno, purchaseorderno, userid)
VALUES ('$invoiceno', '$purchaseorderno', '$userid');";
$result1 = mysqli_query($conn, $sqlString1);
It works but then the invoice no stay as 1. It doesn't increment when I click order. If my idea is wrong, suggestions would be greatly appreciated.
I would do it in two tables not one.
You have invoice and invoice_item Which have a One to Many relationship.
If you make another table for the line items, all you problems evaporate.
Table invoice
id
date
total
status etc...
Table invoice_item
id
invoice_id - foreign key
product_id
quantity
etc...
Selecting them is no problem
SELECT
{fields}
FROM
invoice AS i
JOIN
invoice_item AS l ON i.id = l.invoice_id
WHERE
i.id = :id
And so on....
Then you can just use the Primary key from invoices and your all set. It will also be more robust (less prone to breaking) probably faster, probably easier to code in the long run and so on.
It does add a tiny bit of complexity to the data model, and a bit more caution when doing inserts and deletes and what not, but if you setup the foreign key restraints correctly, use transactions when doing inserts, you should be fine.
UPDATE
Here is a DBfiddle (click it) with a number of examples of how to setup the forign key and how to build the basic table relationship. I just guessed at these fields you can of course make any changes you need to, to add or remove them. This is just for the sake of explaining it.
CREATE TABLE invoice(
id INT(10) unsigned NOT NULL AUTO_INCREMENT,
total DECIMAL(6,2) unsigned NOT NULL,
email VARCHAR(100),
submission_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ( id )
) ENGINE=InnoDB;
CREATE TABLE invoice_item(
id INT(10) unsigned NOT NULL AUTO_INCREMENT,
invoice_id INT(10) unsigned NOT NULL,
product_id INT(10) unsigned NOT NULL,
qty INT(3) unsigned NOT NULL,
sub_total DECIMAL(6,2) unsigned NOT NULL,
PRIMARY KEY ( id ),
CONSTRAINT FK_InvoiceItems FOREIGN KEY(invoice_id) REFERENCES invoice(id) ON DELETE CASCADE ON UPDATE CASCADE,
KEY(product_id)
) ENGINE=InnoDB;
Just a few Query examples:
Insert invoice
#in the example fiddle this is AI #2 so invoice.id=2
INSERT INTO invoice (total,email) VALUES ('100.00','user2#example.com');
Insert related invoice items
#both of these line items have same invoice,
INSERT INTO invoice_item (invoice_id,product_id,qty,sub_total) VALUES ('2','200','7','70.00');
INSERT INTO invoice_item (invoice_id,product_id,qty,sub_total) VALUES ('2','270','2','30.00');
Basic Inner Join (selects all invoices that have items, and their items)
SELECT
i.*, l.id AS invoice_item_id, l.product_id, l.qty
FROM
invoice AS i
LEFT JOIN
invoice_item AS l ON i.id = l.invoice_id;
Count the number of unique Items
SELECT
invoice_id, COUNT(id) AS unique_items
FROM
invoice_item
GROUP BY invoice_id;
Count the number of total items. You can sum, sub_total to get total the same way. You could remove invoice.total if you want to. It can be nice to have the total counted up in there, but you also have to keep it updated when/if you change the number of items in an invoice.
SELECT
invoice_id, SUM(qty) AS total_items
FROM
invoice_item
GROUP BY invoice_id;
Find any invoices without items (its impossible to add items without invoices with the fk constraint, which is exactly what we want)
SELECT
i.*, l.id AS invoice_item_id, l.product_id, l.qty
FROM
invoice AS i
LEFT JOIN
invoice_item AS l ON i.id = l.invoice_id
WHERE
l.id IS NULL;
And Last, Delete an invoice, because of the constraint this will cascade and delete the related items from invoice_item with no extra work,in other words the items are auto-magicaly deleted. I've also found letting the database do the cascade delete is significantly faster then manually deleting them.
DELETE FROM invoice WHERE id=2;
In this data model, I have the invoice_items grouped by products. So for invoice.id #2, we have two items, one with product id #200, which is toy ufo's. The other is #270 which is metallic weather balloons. Tiny Tim got 7 UFO's for $10 each for a sub_total of $70, and then he got 2 weather balloons for $15 each (nothing our government does is cheap).
Ok that is my DB 101 lesson for the day.
UPDATE1
Based on this error
Cannot add or update a child row: a foreign key constraint fails
This is actually a good thing, it's the purpose of the foreign key. I will try to explain
If you do this insert
INSERT INTO invoice (total,email) VALUES ('100.00','user2#example.com');
This creates a row in invoice, it's the purpose of insert. Now because it's Auto Increment Id and this is the first row it's id is 1. Because it's the first row its also the only record in invoice. We can all agree on that, I insert 1 row in a new table, that makes it the first and only row. And it has an AI id of 1
Now if I try to insert
INSERT INTO invoice_item (invoice_id,product_id,qty,sub_total) VALUES ('2','200','7','70.00');
This row has an invoice_id of 2, and we just said we have one invoice with an id of 1. So there is no invoice with an id of 2. This will give you the same error you just got, because you are trying to add an invoice_item without having it's associated invoice, which is something we never want to happen. This is called an "orphan" row because it's parent row does not exist. If we allowed this our Database could be filled with invoice items that have no invoice. Then if we later add an invoice with the id of one of those orphan rows we have just associated things that should not be associated. This is why that error makes sense and why it's a good thing.
The obvious way to fix this is to not insert invoice_items that don't belong to an invoice.
I really hope that makes sense.
So how do we insert invoice_items that do have an invoice?
In PHP you want to insert the invoice then get it's id, then insert the invoice_item. See this page.
http://php.net/manual/en/mysqli.insert-id.php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
//insert invoice
$query = "INSERT INTO invoice (total,email) VALUES ('100.00','user2#example.com')";
$mysqli->query($query);
//insert invoice item with last insert id
$query = "INSERT INTO invoice_item (invoice_id,product_id,qty,sub_total) VALUES ('".$mysqli->insert_id."','200','7','70.00')";
The important part here is to use, $mysqli->insert_id when inserting invoice items. Now if you want to add an invoice item to an existing invoice that was inserted some time ago. Then you just query the invoice, and pull it's id out and use that for the new invoice item.
Hope that helps, enjoy!
We have a table which inserts a row each day and updates it with data.
I have the following query to get the total amount of clicks from the table:
SELECT SUM(`total_clicks`) AS clicks, `last_updated` FROM `reporting` WHERE `unique_id` = 'xH7' ORDER BY `last_updated` DESC
When pulling this info from the database, it is pulling the correct total amount of clicks but the last_updated field is from the first row (yesterday) not the new row inserted today.
How can I go about getting the most recent last_updated field?
If you want the most recent date, use MAX to select it:
SELECT SUM(total_clicks) as clicks, MAX(last_updated) AS last_updated
FROM reporting
WHERE unique_id = 'xH7'
The problem with your version is that ORDER BY happens after aggregating, and aggregation selects non-aggregate columns from arbitrary rows in the table.
If you have only one row per day, then you don't need sum(). Does the following do what you want?
SELECT `total_clicks` AS clicks, `last_updated`
FROM `reporting`
WHERE `unique_id` = 'xH7'
ORDER BY `last_updated` DESC
LIMIT 1;
Your query is an aggregation query that adds up all the clicks in the table. Because it returns only one row, the order by isn't doing anything.
I have a table full of products including price, name, date and ID (PK)
I am in need to update the records when there is a price change (Web scraping script), how would i go about this so that a new row is NOT inserted, rather the price and date are updated.....but the previous values need to remain in the DB....so that when i when i go
"SELECT * FROM items WHERE id ='27'";
Output wanted:
$400 12.4.2013
$314 22.4.2013
$250 12.4.2013
The product will be then displayed with all the updated values since the first price was downloaded, effectively it will be a history of the prices for the item...
the actual results i want to achieve would hopefully be
History for "Product 27" is:
To give more context, when i run my script... ./script.php update
all the new data should be inserted or updated....but old values remain
im not too sure how i should approach this....please provide me with some guidance or assistance
The best way to go about this while keeping a tidy database with easily maintainable and readable data would be to take what #KishorSubedi said in the comment and create a log table.
When you update your price in your Products Table, store the old price, along with its date and ID in the Log Table then when you need to look up all the records for that product you can JOIN the Log Table in your query.
Log Table
| ProductID | Price | Date |
| 27 | $300 | 02.1.2013 |
| 27 | $400 | 03.1.2013 |
This way you can have a nice and neat Products table that is not cluttered with multiples of the same product, and an unobtrusive log table that is easily accessible.
Hope this gives you some guidance on building your site and database.
If you want to keep the old values I would suggest saving them in a seperate table and to use the INSERT statement. You are always adding a new row, so you can not bypass an insert or select into or similar statement.
Table structure:
Items
------------------------------
Id primarykey
Name
Price
------------------------------
Id primarykey autoincrement
ItemId index
AddDate index
Price
Now when you scrape the web you will just insert the new price in the Price table. If you want to select all the prices for an item you can use
SELECT Items.Id
,Items.Name
,Price.Price
,Price.AddDate
FROM Items
LEFT JOIN Price
ON Items.Id=Price.ItemId
WHERE Items.Id='27'
ORDER BY Items.Name ASC, Price.AddDate ASC
And if you just want the latest or current price, you can use
SELECT Items.Id
,Items.Name
,P1.Price
,P1.AddDate
FROM Items
LEFT JOIN Price P1
ON Items.Id=Price.ItemId
LEFT JOIN Price P2
ON P1.ItemId=P2.ItemId
AND P1.Id<P2.Id
WHERE Items.Id='27'
AND P2.Id IS NULL
Add new column for history in 'item' table and each price change append the changed value to this column with a specific format as like date1:price1,date2:price2,....
I am developing a trading site. Users will post some price, $100, $120 for certain products. And I wanted to display highest price for that product, which means current highest price will replace the previous highest price. Tables of mysql is:
user_email //The user who gives price for the product
product//The product name
price//The prices that users posted
chosen//it will be 1 if it is highest otherwise 0
What I wanted to do is that if a user posted $100 for, for example, a book and it is currently highest price (chosen is one for this user) and site displays it. Another user posts $120 for that book and it is now highest price (chosen is 1) and for the previous user's chosen is 0. I could not figure out how to compare prices for certain products and change all of the lower prices chosen 0 for that product. How can i do this? Sorry i am new:(
You can use the MAX function from MySQL to get the highest number of a colomn. Example :
SELECT MAX(field) FROM `table_name`
You just need to add WHERE and it will confine the search fields.
After, you update everything else with something like this
UPDATE `table_name` SET `field` = 0 WHERE `product` = "X" AND `id` != Y
X will be the product ID and Y will be the ID from the first query.
Something like this will do you,
$q = $dbc -> prepare("SELECT price FROM table_name ORDER BY price DESC LIMIT 1");
Using the order by clause will get you the highest price available, now store it in a variable like so,
$q -> execute();
$highest = $q -> fetch(PDO::FETCH_ASSOC);
Now change all the other users' price to zero,
$q = $dbc -> prepare("UPDATE table_name SET price = 0 WHERE price != ?");
$q -> execute(array($highest));
Now this will eliminate the need for the chosen column in your database, as you only need the highest price for a bid, which can easily be found using the opposite of the above query with another parameter for the BID ID.
This example is using PDO which I highly suggest if you are making a trading site, I hope this was what you wanted to achieve,
Happy coding,
Currently CustomerID's start at 1 while the first Order generated has OrderID 100000001.
Is there any way of altering these fields, so the first customer created has
customer number 900000001 and the first order created has OrderID 900000001?
By changing the increment_last_id in eav_entity_store table, you can control the starting number of customer number, Order Number, Invoice Number, and shipping Memo Id.
Paste this code to Phpmyadmin to change the Order Number
UPDATE eav_entity_store
INNER JOIN eav_entity_type ON eav_entity_type.entity_type_id = eav_entity_store.entity_type_id
SET eav_entity_store.increment_last_id='XXXXX'
WHERE eav_entity_type.entity_type_code='order';
Replace the X‘s with your desired order number
for more detail you can go to this link for that:
click here
You may try to alter the AUTO_INCREMENT of the table before adding new customer or order:
$magento_db = Mage::getSingleton('core/resource')->getConnection('core_write');
$magento_db->query("ALTER TABLE customer_entity AUTO_INCREMENT = ".$desiredId);