Update MS Access table empty fields based on same table - ms-access

In MS Access database, I'm working with a table that has rows. In some cases not all columns of the rows are filled. I want to create an update query to update the values of the empty fields with data from other rows where the column is not empty.
googled the question but no satisfying answer has been found. Can someone show me how the query should be build?
Current table looks like
| Invoicenumber | Customer | Date |
|---------------|----------|---------|
| 5 | 12 | 12-6-19 |
| 5 | | 12-6-19 |
| 5 | | 12-6-19 |
| 5 | | 12-6-19 |
| 6 | 18 | 15-6-19 |
| 6 | | 15-6-19 |
| 6 | | 15-6-19 |
| 7 | 20 | 20-6-19 |
| 7 | | 20-6-19 |
I need the table to look like this after updating:
| Invoicenumber | Customer | Date |
|---------------|----------|---------|
| 5 | 12 | 12-6-19 |
| 5 | 12 | 12-6-19 |
| 5 | 12 | 12-6-19 |
| 5 | 12 | 12-6-19 |
| 6 | 18 | 15-6-19 |
| 6 | 18 | 15-6-19 |
| 6 | 18 | 15-6-19 |
| 7 | 20 | 20-6-19 |
| 7 | 20 | 20-6-19 |

You can do it with just SQL by joining the table to itself:
UPDATE
Invoices
INNER JOIN Invoices AS Inv2
ON Invoices.InvoiceNumber = Inv2.InvoiceNumber
SET
Invoices.Customer = Inv2.Customer
WHERE
(Invoices.[Customer] Is Null)
AND (Inv2.Customer IS NOT NULL)

You can place a Switch statement into the update to choose the value to update based on the state of the CUSTOMER field.
Update TestTable
Set CUSTOMER = Switch(CUSTOMER is Null,OTHER_FIELD,CUSTOMER = '',OTHER_FIELD,CUSTOMER<>'',CUSTOMER)
This statement will update the CUSTOMER field to the OTHER_FIELD where CUSTOMER is blank or CUSTOMER is Null. If CUSTOMER has a value, it sets it to that value (essentially leaving it as the same.)
The 'SWITCH' statement is Access's version of a 'Switch' or 'Select Case' in code, where the first parameter is the condition to check, the parameter after it is the value to take if the previous condition returns true. So...
Switch(1=1,'YES',2=1,'NO', case 3, return 3, case 4, return 4, etc., etc.,)
would return the 'YES' because 1 is equal to 1.
There would be a more eloquent way to do this with code, but in an Access query, I don't know any other way.

Try using domain aggregate function to pull the Customer:
UPDATE table1 SET table1.Customer = DMax("Customer","table1","Invoicenumber=" & [Invoicenumber])
WHERE (((table1.Customer) Is Null));

Question answered by solution mentioned by #John Mo. Used his code to update table with data available within the table.

Related

Get rows with condition on last grouping row

I have table favourite_products with schema like below. I need to count how many people (account_id) like product with id = 12. But the condition is that person marked product as liked on last time.
In this example user with id = 1 marked product 12 as positive for the first time, but then he marked is a non-positive so this value shouldn't be returned. The following example should return 2 rows (for user_id = 5 and user_id = 8). I heard about window function but have mysql in version 5.7 and I can't upgrade it. Do you have some ideas how to write this query?
| id | user_id | product_id | positive |
| 1 | 1 | 12 | 1 |
| 2 | 1 | 12 | 0 |
| 3 | 1 | 15 | 1 |
| 4 | 5 | 12 | 1 |
| 5 | 5 | 12 | 1 |
| 6 | 11 | 18 | 1 |
| 7 | 8 | 12 | 1 |
| 8 | 8 | 12 | 1 |
Following approach should work for all the cases, including the case when a product was disliked and then liked again at the end.
In a Derived table, we can get the maximum id value for every user_id and product_id = 12. This result-set will be joined to the main table appropriately. This will fetch us the complete row (recent activity done by user for a product).
Now, we can consider only those users where the last activity is positive.
Query
SELECT fp.user_id
FROM favourite_products AS fp
JOIN (SELECT user_id,
Max(id) AS max_id
FROM favourite_products
WHERE product_id = 12
GROUP BY user_id) AS dt
ON dt.user_id = fp.user_id
AND dt.max_id = fp.id
AND fp.positive = 1;
Result
| user_id |
| ------- |
| 5 |
| 8 |
View on DB Fiddle

How to loop a MySQL query and return the result as a single result set ? use function or prcedure?

I have simple query that returns the count and sum of particular user based on the user id
select count(id) links ,sum(download_count) dowloads, user_id from file_list_user where user_id = 6
How can I write a function / procedure that loops the same query for all user_id 's?
file_list_user table structure
+------+----------------+---------+
| id | download_count | user_id |
+------+----------------+---------+
| 844 | 20 | 6 |
| 1192 | 4 | 7 |
| 1305 | 1 | 6 |
+------+----------------+---------+
The unique user_id's are is stored in another table user
user table structure
+---------+-------------+
| user_id | user_name |
+---------+-------------+
| 6 | clain |
| 8 | Mayor |
| 9 | JohnRock |
+---------+-------------+
I have searched through most of the answers in Stack Overflow but none of them addressed my scenario. Some are overly complicated even to understand. I am looking for a simple solution so that I can call this function and return the result as a single result set table similar to below
+-------+----------+---------+
| links | dowloads | user_id |
+-------+----------+---------+
| 11 | 36 | 6 |
+-------+----------+---------+
| 15 | 10 | 8 |
+-------+----------+---------+
| 60 | 90 | 9 |
+-------+----------+---------+
use group by clause instead of where clause
select count(id) links ,sum(download_count) dowloads, user_id from file_list_user group by user_id

Distinct order-number sequence for every customer

I have table of orders. Each customer (identified by the email field) has his own orders. I need to give a different sequence of order numbers for each customer. Here is example:
----------------------------
| email | number |
----------------------------
| test#com.com | 1 |
----------------------------
| example#com.com | 1 |
----------------------------
| test#com.com | 2 |
----------------------------
| test#com.com | 3 |
----------------------------
| client#aaa.com | 1 |
----------------------------
| example#com.com | 2 |
----------------------------
Is possible to do that in a simple way with mysql?
If you want update data in this table after an insert, first of all you need a primary key, a simple auto-increment column does the job.
After that you can try to elaborate various script to fill the number column, but as you can see from other answer, they are not so "simple way".
I suggest to assign the order number in the insert statement, obtaining the order number with this "simpler" query.
select coalesce(max(`number`), 0)+1
from orders
where email='test1#test.com'
If you want do everything in a single insert (better for performance and to avoid concurrency problems)
insert into orders (email, `number`, other_field)
select email, coalesce(max(`number`), 0) + 1 as number, 'note...' as other_field
from orders where email = 'test1#test.com';
To be more confident about not assign at the same customer two orders with the same number, I strongly suggest to add an unique constraint to the columns (email,number)
create a column order_number
SELECT #i:=1000;
UPDATE yourTable SET order_number = #i:=#i+1;
This will keep incrementing the column value in order_number column and will start right after 1000, you can change the value or even you can even use the primary key as the order number since it is unique all the time
I think one more need column for this type of out put.
Example
+------+------+
| i | j |
+------+------+
| 1 | 11 |
| 1 | 12 |
| 1 | 13 |
| 2 | 21 |
| 2 | 22 |
| 2 | 23 |
| 3 | 31 |
| 3 | 32 |
| 3 | 33 |
| 4 | 14 |
+------+------+
You can get this result:
+------+------+------------+
| i | j | row_number |
+------+------+------------+
| 1 | 11 | 1 |
| 1 | 12 | 2 |
| 1 | 13 | 3 |
| 2 | 21 | 1 |
| 2 | 22 | 2 |
| 2 | 23 | 3 |
| 3 | 31 | 1 |
| 3 | 32 | 2 |
| 3 | 33 | 3 |
| 4 | 14 | 1 |
+------+------+------------+
By running this query, which doesn't need any variable defined:
SELECT a.i, a.j, count(*) as row_number FROM test a
JOIN test b ON a.i = b.i AND a.j >= b.j
GROUP BY a.i, a.j
Hope that helps!
You can add number using SELECT statement without adding any columns in table orders.
try this:
SELECT email,
(CASE email
WHEN #email
THEN #rownumber := #rownumber + 1
ELSE #rownumber := 1 AND #email:= email END) as number
FROM orders
JOIN (SELECT #rownumber:=0, #email:='') AS t

MySQL historical data lookup

I've been looking around and trying to get this to work but I can't seem to get it. I have 2 tables:
TABLE: products
| id | name | some more values |
|----|-----------|------------------|
| 1 | Product 1 | Value 1 |
| 2 | Product 2 | Value 2 |
| 3 | Product 3 | Value 3 |
TABLE: value
| pid | value | stamp |
|-----|-----------|------------------|
| 1 | 7 | 2015-07-11 |
| 2 | 4 | 2015-07-11 |
| 3 | 8 | 2015-07-11 |
| 1 | 9 | 2015-07-21 |
| 2 | 4 | 2015-07-21 |
| 3 | 6 | 2015-07-21 |
First table simply has a list of products, second table has a value for each product (by pid), and the timestamp the value. note: timestamps are not every day, nor are they evenly spaced.
What I would like, is a resulting table like this:
| id | name | some more values | value now | value last month |
|----|-----------|------------------|-----------|------------------|
| 1 | Product 1 | Value 1 | 9 | 7 |
| 2 | Product 2 | Value 2 | 4 | 4 |
| 3 | Product 3 | Value 3 | 6 | 8 |
where 'value now' is the value of the newest timestamp, and the 'value last month' is the value of the timestamp closest to the newest timetamp - 30 days. Keep in mind that -30 days might not have a specific timestamp, the query will need to find the closest timestamp. (looking only up or down doesn't matter, it's an approximation.)
I have made some huge queries but I'm pretty sure there must be an easier way... Any help would be appreciated.
Assuming you get last month and year by PHP or by mysql function, here is a not checked query I hope it will work on first time:
SELECT *, v_now, v_lastmonth FROM products p
LEFT JOIN (SELECT `value` AS v_now FROM value ORDER BY stamp DESC) AS v_now ON p.id=v_now.pid
LEFT JOIN (SELECT `value` AS v_lastmonth FROM value
WHERE month(stamp)='$month' AND year(stamp)='$year'
ORDER BY stamp DESC) AS v_now ON p.id=v_now.pid
You can use group by to get one row for each product result.

SQL INSERT INTO query syntax

I am trying to run an MySQL query to copy over data from an old table (ps__product_review/rate) to a new table (ps_product_comment/grade) based on review ID (id_product_comment). But I am a bit lost on the SQL query, this is what I have but keep getting errors.
INSERT INTO ps_product_comment [(grade)]
SELECT rate
FROM ps__product_review
[WHERE ps__product_review.id_product_comment=ps_product_comment.id_product_comment];
Can anyone help write the correct query?
Edit:Essentially I am trying to populate the Grade column in the new table below.
Old table (ps__product_review)
+--------------------+----------+-----+
| id_product_comment | Comment | Rate|
+--------------------+----------+-----+
| 1 | Good | 2 |
| 2 | Great | 5 |
| 3 | OK | 3 |
| 4 | Brill | 4 |
| 5 | OK | 3 |
| 6 | Average | 2 |
| 7 | Bad | 1 |
+--------------------+----------+-----+
New Table (ps_product_comment)
+--------------------+----------+-------+
| id_product_comment | Comment | Grade |
+--------------------+----------+-------+
| 1 | Good | |
| 2 | Great | |
| 3 | OK | |
| 4 | Brill | |
| 5 | OK | |
| 6 | Average | |
| 7 | Bad | |
+--------------------+----------+-------+
If you want to update table with data from another table, use UPDATE with JOIN
UPDATE ps_product_comment
JOIN ps__product_review
ON ps__product_review.id_product_comment = ps_product_comment.id_product_comment
SET ps_product_comment.grade = ps__product_review.rate;
Remove the square brackets and I think you are missing the JOIN(since you are using that in your where clause):
INSERT INTO ps_product_comment (grade)
SELECT rate
FROM ps__product_review inner join ps_product_comment on
ps__product_review.id_product_comment=ps_product_comment.id_product_comment;