Mysql insert on duplicate key update with where alternative - mysql

I would like to know if there is a way to use insert into...on duplicate key without use as parameter the primary key of the table, for example I have the following table :
+----+------------+------+--------+
| id | product_id | year | name |
+----+------------+------+--------+
| 1 | 5 | 2018 | Sword |
| 2 | 7 | 2018 | Shield |
+----+------------+------+--------+
I have an array for insert in that database (PHP - PDO).
This array have 3 items :
the sword
the shield
and the potion
For example, with id as primary key, I would like to know if its possible to perform something like INSERT ... ON DUPLICATE KEY UPDATE
instead using the id (because in this moment I'll not have the id)
I can use a where or something like that, cross the product_id and the year would be perfect.

Related

MySQL relations with restrictions

I have this table structure and simple relationships:
and sample data in the table:
Company
Company names are unique and should not be repeated:
+------------+---------------+
| Company_ID | Company_name |
+------------+---------------+
| 1 | Company_name1 |
+------------+---------------+
| 2 | Company_name2 |
+------------+---------------+
Location
(Locations should be assigned to a specific company):
+-------------+------------+-------------------------+
| Location_ID | Company_ID | Location_name |
+-------------+------------+-------------------------+
| 1 | 1 | Company1_Location_name1 |
+-------------+------------+-------------------------+
| 2 | 1 | Company1_Location_name2 |
+-------------+------------+-------------------------+
| 3 | 2 | Company2_Location_name1 |
+-------------+------------+-------------------------+
| 4 | 2 | Company2_Location_name2 |
+-------------+------------+-------------------------+
Data
The data in the table should depend on the selected company, and the locations should be only those that occur in the company:
+---------+-------------+------------+------------+------+
| Data_ID | Location_ID | Company_ID | data_value | date |
+---------+-------------+------------+------------+------+
| 1 | 1 | 1 | 5 | date |
+---------+-------------+------------+------------+------+
| 2 | 2 | 1 | 2 | date |
+---------+-------------+------------+------------+------+
| 3 | 3 | 2 | 3 | date |
+---------+-------------+------------+------------+------+
| 4 | 2 | 1 | 1 | date |
+---------+-------------+------------+------------+------+
| 5 | 4 | 2 | 6 | date |
+---------+-------------+------------+------------+------+
| 6 | 4 | 2 | 7 | date |
+---------+-------------+------------+------------+------+
The main dependencies that should be met:
Company names should be unique and attempts to add the same company should be blocked
Location names should be assigned to a specific company, but they may repeat and a location may appear in several companies but have a different Location_ID
Adding values to the date table should depend on:
company (we choose a specific company for which we add values)
locations (locations must depend on company)
For example:
When adding values for a company with Company_ID = 1, I should only be able to add Location_ID that occur under that company.
If I want to add a value in the data table for Company_name1 then the only available values for the Location_ID column in the data table, should be: Company1_Location_name1 and Company1_Location_name2 and I can't have values there from another company (i.e. Company2_Location_name1 and Company2_Location_name2)
At the moment it works badly:
when adding values to the data table I can select a company, but then I have locations available and I can add values that do not make sense - for Company_name1 I can add a location from Company_name2 but it should be blocked.
How can I solve such a problem? Add some additional table which will be responsible for particular pairing?
Depends what database you use.
A simpler way would be to just create a unique constraint on the table field, this will also enforce it for updates too and remove the need for a trigger. Just do:
Example for MSSQL:
ALTER TABLE [dbo].[Company]
ADD CONSTRAINT [Company_name] UNIQUE NONCLUSTERED
(
[CompanyID], [Company_name]
)
and then you'll be in business. You will be not able to add 2 company with the same name.
You can find another examples here : Trigger to prevent Insertion for duplicate data of two columns
This is exacly what you are looking for :)
#EDIT 1
OK so if you want example for MARIADB here we go :
Create unique Contraint - Using a CREATE TABLE statement
The syntax for creating a unique constraint using a CREATE TABLE statement in MariaDB is:
CREATE TABLE table_name
(
column1 datatype [ NULL | NOT NULL ],
column2 datatype [ NULL | NOT NULL ],
...
CONSTRAINT constraint_name UNIQUE (uc_col1, uc_col2, ... uc_col_n)
);
table_name
The name of the table that you wish to create.
column1, column2
The columns that you wish to create in the table.
constraint_name
The name of the unique constraint.
uc_col1, uc_col2, ... uc_col_n
The columns that make up the unique constraint.
In your example :
CREATE TABLE Company
( Company_ID INT(11) PRIMARY KEY AUTO_INCREMENT,
Company_name VARCHAR(250) NOT NULL,
CONSTRAINT company_name_unique UNIQUE (Company_name)
);
In this example, we've created a unique constraint on the Company table called company_name_unique. It consists of only one field - the Company_name field.

How to refer to a record in a table without a primary key

I have created a table without any primary key and it contains some exactly identical records.
How do I update or view a record using SQL statements?
The structure of my table is like :-
+----------------+-------+---------+----------+
| Name | class | section | City |
+----------------+-------+---------+----------+
| Mohit Yadav | 10 | A | Neemrana |
| Mohit Yadav | 10 | A | Neemrana |
| Janvi Yadav | 10 | A | Neemrana |
| Jaspreet Singh | 11 | B | Jaipur |
| Jaspreet Singh | 11 | B | NULL |
+----------------+-------+---------+----------+
Can we refer to the second record and change the class to 11th using update command.
Something like this would work:-
UPDATE <SOMETBL> SET CLASS='11' WHERE {INDEX_OF_RECORD=1};
Please rectify the part written inside the curly brackets so that I can refer to a record using its index.
First of all, not having a primary key is not a good idea at all, it is always a good practice to have the so-called ID column. But as it is the case now, there would be some ways.
The first and second records are exactly identical, as you said. So there is no actual difference between them to distinguish. So it doesn't matter at all to change the first row or the second one, and a good approach to achieve so is to put limitation on number of rows the update query affect on. you can simply use this
UPDATE <SOMETBL> SET CLASS='11' WHERE
NAME ='Mohit Yadav' AND
CLASS ='10' AND
SECTION ='A' AND
CITY ='Neemrana'
LIMIT 1;
The easiest way to solve this is to add an auto incrementing column and then refer to the record by its now unique int:
ALTER TABLE `t` ADD `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY

Better way to design payment database with multiple payment methods

I am trying to make a payment/transaction database for a pretend online store (just trying to learn). 1 payment can purchase 1 to many items. 1 payment can only have 1 payment method.
To keep the example simple, there are 2 payment methods, PayPal and Bitcoin. Each payment method has different attributes, hence they must be different tables.
I have my payments table which tells me what transaction bought what item/s. However, you can see that if the paypal_idis NULL then the bitcoin_id column is not. This means there are a lot of NULL's which I think is not a good design. How can I have good design in a case like this?
paypal table
paypal_id | txn_id | buyer_email | amount
1 | 3sd7fgudf23sdf34 | john#mail.com | 50.00
2 | 45shfik45345fg2s | mike#gmail.com | 100.00
bitcoin table
bitcoin_id | txn_id | amount
1 | 34327yhujndreygdiusfsdf324 | 0.19203
2 | sdfgurjibdsfhubhsdfinjo332 | 0.04123
items table
item_id | item name | price
1 | ball | 50.00
2 | shirt | 50.00
payments
payment_id | item_id | paypal_id | bitcoin_id
1 | 1 | 1 | NULL
2 | 1 | 2 | NULL
3 | 2 | 2 | NULL
4 | 1 | NULL | 1
5 | 1 | NULL | 1
6 | 1 | NULL | 2
Your design is fine. But you might want to consider an alternative where you have a payment_transactions table and then related tables that use the same primary key:
create table payment_transactions (
payments_transactions_id int auto_increment primary key,
type varchar(255),
payment_datetime datetime, -- probably common to all payment methods
. . . other columns if you like,
unique (type, payments_transactions_id) -- this will be used for foreign key references
);
create table bitcoin_payments (
bitcoin_payments_transaction_id int primary key,
type varchar(255) generated always as ('bitcoin'),
. . . , -- columns specific to bitcoins
foreign key (type, bitcoin_payments_transaction_id) references payments (type, payments_transactions_id)
);
-- similar for paypal
Then your payments table can have a foreign key to payments.
This handles much of the data modeling issue;
You have proper declared foreign key relationships.
Only one column is needed in payments regardless of the number of types.
You can easily introduce new types.
This guarantees one type per payment (via the inclusion of type in the foreign key reference).
One downside is that you need to insert each transaction twice. First into the payment_transactions table and then into the proper table.
Payments are actually more complicated than you present. A more realistic data model would handle:
Transaction status.
Retries.
Partial payments.
Once you get the basic structure down, you might want to try adding in new capabilities.

Add a temporary column in mysql who's entries are counts of same entries of a table

So I have this database which contains in it a list of files. Files can be updated, but the previous versions are still held on to in case of rollbacks. What I want to know is how would I add a temporary column that contains the number of previous versions for that file.
Essentially, how would I crate a temporary column in mysql who's entries depend on something within the main table?
CREATE TABLE Files(
file_id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT,
student_id INTEGER,
group_id INTEGER,
submission_number INTEGER,
submission_type VARCHAR(10),
FOREIGN KEY (student_id) REFERENCES Student (student_id) ON DELETE CASCADE,
FOREIGN KEY (group_id) REFERENCES Groups(group_id)ON DELETE CASCADE
);
A submission is defined by its submission_number and submission_type. So submission_type 0 would be an assignment, 1 would be a project, 2 would be a quiz and so on. submission_number would be which assignment of that submission type we are uploading. So for example, the third quiz will have a submission_type =2 and a submission_number = 3. we can update a file, so we can upload a new file with the same submission_type and submission_number. What I want to return is a table which contains the number of times each submission had an upload.
So if i had the following table
+---------+------------+----------+-------------------+-----------------+
| file_id | student_id | group_id | submission_number | submission_type |
+---------+------------+----------+-------------------+-----------------+
| 1 | 10049 | 1 | 1 | assignment |
| 2 | 10032 | 1 | 1 | assingment |
| 3 | 10032 | 1 | 2 | quiz |
| 4 | 10032 | 1 | 3 | assingment |
+---------+------------+----------+-------------------+-----------------+
I would want to return the table
+-------------------+-----------------+-------+
| submission_number | submission_type | count |
+-------------------+-----------------+-------+
| 1 | assignment | 2 |
| 2 | quiz | 1 |
| 3 | assignment | 1 |
+-------------------+-----------------+-------+
Another way to think about it, if submission_number and submission_type were coordinates instead, say x,y then i want to count the number of times the same point appears in the table. So the point (1,assignment) appeared twice thus the count is 2.
You don't need another table just to do that. Just write a query using GROUP BY.
SELECT submission_number, submission_type, COUNT(file_id) FROM Files GROUP BY submission_number, submission_type;
working demo

How to select multiple entries with the same value in one column in T-SQL

So, I am working in Visual Studio 2013. And I have a table like this:
id | fk | data
----------------------
1 | 1 | something1
2 | 1 | something2
3 | 1 | something3
. | . | ...
. | . | ...
6 | 2 | ...
The fk is a foreign key to another table. I want to select all the rows which have the same fk. There is an undefined number of the same fk entries (there could be 5 rows with value 1 and 3 rows with value 2, etc.) But, I want to be able to switch said fk in my program so that when i put the DB in a Form in Visual Studio, clicking a button next would get me the next value of the fk. For example, I would like the first result to come out like this:
id | fk | data
----------------------
1 | 1 | something1
2 | 1 | something2
3 | 1 | something3
And when I click next to get me to the next entry, the result would be:
id | fk | data
----------------------
6 | 2 | ....
7 | 2 | ....
Is there a way in SQL to combine just the results with the same fk value? All of the solutions I have found so far gave me all of the fk values (all entries). I haven't found a way to get just all the entries with a single, unique value in the fk column.
You're looking for a basic SELECT statement with a WHERE clause:
SELECT
id, fk, data
FROM
your_table_name
WHERE
fk = 1
I can't help you with the VisualStudio stuff though, but you'll just have to repeat the same query incrementing the fk value in the WHERE clause