Number of rows that are using the foreign key - mysql

I have a problem with counting the number of items/rows that are using the foreign key.
For example.
Table "A" has a foreign key of "group_id" and there is a row with "group_id" of "5" and a couple of items/posts/rows in table "B" are using the foreign key (in this case the ID of "5"). How would I know how to cont the rows that are using that "group_id"?
Here's what I mean.
Thanks very much.
UPDATE
Here is a sketch that explains my problem
PK = Primary Key
FK = Foreign key

You can query the number of rows like this:
SELECT group_id, COUNT(*) FROM table_B GROUP BY group_id;
Your image seems to show that you want table_A to keep the count persistently as an attribute column.
Some people design triggers for this. For example, in an INSERT trigger on table_B, increment the count attribute column of table_A by 1. In a DELETE trigger on table_B, decrement the count column of table_A by 1.
This sort of works, but it causes more overhead for inserts and deletes, and it causes more exclusive locking on table_A.
It's easier to do the SELECT query that I showed above.

Related

Copying from one table to other, how to enforce foreign key check on the whole data set but not on separate rows?

I'm using MySQL. Let's assume I have a table hierarchy with two columns: id, parent_id.
The parent_id refers to id of other row of the same table, so I have the foreign key there.
The hierarchy table contains some data, but they are not relevant now.
I also have a second table called new_hierarchy_entries that has the same columns, but there are no foreign key restrictions set.
new_hierarchy_entries contains:
id parent_id
2 1
1 null
Now I want to copy all the rows from new_hierarchy_entries into hierarchy. When I run naively:
INSERT INTO hierarchy SELECT * FROM new_hierarchy_entries
I get error: Cannot add or update a child row: a foreign key constraint fails (my_db.hierarchy, CONSTRAINT hierarchy_ibfk_2 FOREIGN KEY (parent_id) REFERENCES hierarchy (id))
Of course, if the rows are inserted one by one, the first row (id=2, parent=1) cannot be inserted, because there is no row with id=1 in table hierarchy.
On the other hand, if all rows were added at once, then the constraints would be satisfied. So how can I copy the rows in such a way that I'm sure that constraints are satisfied after the copying, but they may not be satisfied while copying?
Sorting rows of new_hierarchy_entries by id will not help. I cannot assume that parent_id < id in the same row.
Sorting rows of new_hierarchy_entries by the hierarchy (using tree terminology, give me leaves first, then their parents etc.) would help, but I'm not sure how to do that in MySQL query.
I played with the idea of temporarily turning the FOREIGN_KEY_CHECKS off. But then I could insert inconsistent data and I wouldn't find out. Turning FOREIGN_KEY_CHECKS on doesn't make the database check consistency of all the data. It would take too much resources anyway.
This is tricky. I don't know any way to make MySQL re-check foreign key references after enabling FOREIGN_KEY_CHECKS.
You could check yourself for orphan rows, and if there are any, roll back.
BEGIN;
SET SESSION FOREIGN_KEY_CHECKS=0;
INSERT INTO hierarchy SELECT * FROM new_hierarchy_entries;
SET SESSION FOREIGN_KEY_CHECKS=1;
SELECT COUNT(*) FROM hierarchy AS c
LEFT OUTER JOIN hierarchy AS p ON p.id=c.parent_id
WHERE p.id IS NULL;
-- if count == 0 then...
COMMIT;
-- otherwise ROLLBACK and investigate the bad data
One other possibility is to use INSERT with the IGNORE option, which will skip failed rows. Then repeat the same statement in a loop, as long as you see "rows affected" more than 0.
INSERT IGNORE INTO hierarchy SELECT * FROM new_hierarchy_entries;
INSERT IGNORE INTO hierarchy SELECT * FROM new_hierarchy_entries;
INSERT IGNORE INTO hierarchy SELECT * FROM new_hierarchy_entries;
...

Upserting to MySQL, but with multiple columns and unique index as duplicate check?

I saw a lot of people have asked about upserting (this, this, this, this, this, this, and more and even the official doc).
However, something that is not explained well enough for newbies to understand is how to create the duplicate key using primary key or unique indexes.
What I need:
If a table1's unique combination of 3 columns (attributeId, entityId, carId) has a duplicate in table2, then update the value column. Else take table1's row and insert it into table2.
The attributeId, entityId, carId combination will be unique for every row.
ie: If a row has columns as 1,2,5, then no other row will have 1,2,5. But another row might have 5,1,2 or 3,4,2 etc.
The dilemma here is about creating the unique index. Is it sufficient to just do it like this:
CREATE INDEX PIndex ON table1 (attributeId, entityId, carId);
or is it necessary to delete all other indexes and then create this index and then run a query like this? (pseudocode below):
INSERT INTO table1 (attributeId, entityId, carId, value, name)
VALUES (table2.attributeId,table2.entityId,table2.carId,table2.value,table2.name)
ON DUPLICATE KEY UPDATE value=VALUES(value);
The basic logic being:
If for a row in table2, there is a corresponding row in table1 with exactly the same values for attributeId, entityId and carId, then update the value column in table1 with the value of the value column in table2. If there is no corresponding row, then take the row of table2 and append it to table1.
Seems like the specification is for two different operations: 1) an UPDATE of existing rows in table1, and 2) an INSERT of new rows into table2.
The specification says "update the value column"... we take that to mean update the value column in the row of table1.
The specification also says "insert ... into table2.
Confusingly, the specification also shows an example pseudo-code INSERT INTO table1.
To perform an UPDATE of table1 based on values in table2, assuming we are going to ignore rows that have a NULL value in any of the three columns...
UPDATE table1 t
JOIN table2 s
ON t.attributeid = s.attributeid
AND t.entityid = s.entityid
AND t.carid = s.carid
SET t.value = s.value
If there are "duplicates" in table2 (i.e. multiple rows in table2 with the same values of the three columns attributeid, entityid and carid, it is indeterminate which of those rows value will be taken from.
To insert a row that is found in table2 but "missing" from table1 (again assuming those three columns may not be unique in table2), we can use an anti-join pattern to eliminate rows which already have a "match" in table1.
For example:
INSERT INTO table1 (attributeid, entityid, carid, value)
SELECT v.*
FROM ( SELECT s.attribute_id
, s.entity_id
, s.carid
, s.value
FROM table2 s
LEFT
JOIN table1 r
ON r.attributeid = s.attributeid
AND r.entityid = s.entityid
AND r.carid = s.carid
WHERE r.attributeid IS NULL
AND s.attributeid IS NOT NULL
AND s.entityid IS NOT NULL
AND s.carid IS NOT NULL
GROUP
BY s.attributeid
, s.entityid
, s.carid
) v
If there are "duplicates" in table2 (i.e. multiple rows in table2 with the same values of the three columns attributeid, entityid and carid, it is indeterminate which row value will be taken from.
If there are other UNIQUE constraints defined on other columns, or combinations of columns, the statement has a potential to throw a "duplicate key" error. (Without knowing the key definitions, we're kinda flying blind.) We could add the IGNORE keyword if we want the statement to succeed, just ignoring rows that fail to insert due to "unique key" violations.)
Again, if there are rows in table2 with the same values in the the three columns (no indication is given that this combination of columns is unique in table2), it's indeterminate which of those rows value will be taken from.
The same operations can be performed in the opposite direction, swapping all occurrences of the table references table1 and table2 in the queries.
It's not necessary to add a UNIQUE KEY to either of the tables to perform these operations. There would (likely) be a performance benefit to having a suitable index defined, with those three columns as the leading (first) columns in the index. (That doesn't necessarily need to be a UNIQUE index for this operation.)
If that combination of columns should be unique, then by all means add a UNIQUE KEY on that combination of columns. But the specified operations can be performed without a UNIQUE KEY defined.
The MySQL INSERT ... ON DUPLICATE KEY syntax does require at least one PRIMARY KEY or UNIQUE KEY to operate. If there are multiple UNIQUE KEY constraints on the target table, and an INSERT would violate two or more of the unique key constraints, I believe it's indeterminate which of those keys will be used in the UPDATE action. Personally, I'd tend to steer clear of using that syntax on a table with more than one UNIQUE KEY defined.
You can use the syntax
ALTER IGNORE TABLE table1 ADD UNIQUE INDEX PIndex (attributeId, entityId, carId);
According to the documentation:
If IGNORE is specified, only one row is used of rows with duplicates on a unique key. The other conflicting rows are deleted. Incorrect values are truncated to the closest matching acceptable value.
Unfortunately it does not specify which value will be kept. Doing some tests it seems like it keeps the first occurrence, but you can never be sure.
If which entry will be dropped does not bother you this is the easiest solution, otherwise if you want more control it would be better to go through a temporary table.
The command CREATE UNIQUE PIndex ON table1 (attributeId, entityId, carId); (note the added UNIQUE) will simply fail on the first duplicate key, and no option to manage duplicates is available.

Remove duplicate values without ID

I have a table like this:
uuid | username | first_seen | last_seen | score
Before, the table used the primary key of a "player_id" column that ascended. I removed this player_id as I no longer needed it. I want to make the 'uuid' the primary key, but there's a lot of duplicates. I want to remove all these duplicates from the table, but keep the first one (based off the row number, the first row stays).
How can I do this? I've searched up everywhere, but they all show how to do it if you have a row ID column...
I highly advocate having auto-incremented integer primary keys. So, I would encourage you to go back. These are useful for several reasons, such as:
They tell you the insert order of rows.
They are more efficient for primary keys.
Because primary keys are clustered in MySQL, they always go at the end.
But, you don't have to follow that advice. My recommendation would be to insert the data into a new table and reload into your desired table:
create temporary table tt as
select t.*
from tt
group by tt.uuid;
truncate table t;
alter table t add constraint pk_uuid primary key (uuid);
insert into t
select * from tt;
Note: I am using a (mis)feature of MySQL that allows you to group by one column while pulling columns not in the group by. I don't like this extension, but you do not specify how to choose the particular row you want. This will give values for the other columns from matching rows. There are other ways to get one row per uuid.

Insert if not exist and Update if exist

I have three columns on my database table
user_id, post_id, and vote
I want to insert a new data if user_id and post_id don't exist. But if both columns user_id and post_id exist i will be able to update 'vote' column value. I set user_id to be unique but it proves to be not working since i want user to insert votes on different post.
The query below only updated the value of vote since user_id already exist. I want to have it updated if and only if user_id and post_id existed
I used this sql query
INSERT INTO polls (user_id,post_id,vote) VALUES (1,2,5)
ON DUPLICATE KEY UPDATE vote= ?;
Here's my problem
You must create unique key combination
Create unique index your_index_name on yourtable (field_one,field_two),
then do the insert into , on duplicate key logic
It is absolutely logical that your code does not work as intended, because your only key is user_id, thus if you want to check the uniqueness of user_id AND post_id, then you should set it as so.
Don't think you can do it purely in MySQL :*( post_id would have to be unique and you said that does not fit your business logic. Furthermore, if multiple keys are detected, they are joined by an OR in the resulting query, which will further complicate things for you. Here's an excerpt from the manual, where a and b are keys involved in the ON DUPLICATE KEY query:
If a=1 OR b=2 matches several rows, only one row is updated. In general, you should try to avoid using an ON DUPLICATE KEY UPDATE clause on tables with multiple unique indexes.

check duplication using mysql select

I have a category say ecommerce.add ebay and amazon.when i update ebay as amazon,it should n't update.How do i d it?
I suggest you check out unique indexes and primary keys. These will cause an insert or update to fail rather that allow duplicate entries to be made.
CREATE UNIQUE INDEX name_unique ON tablename (name(10));
Replace name_unique with the name you want for the index, tablename with the name of your table, and name(10) with the column name and how many characters you want to be unique (the length of the column if you want the entire value to be unique).