I have a problem with my query. I have 2 tables with relationship.
table category
CategoryId name
1 category1
2 category2
table order
orderId CategoryId date Description
1 2 2014-10-10 okay
2 1 2014-10-10 okay2
3 1 2014-10-10 okay3
my question is how to set categoryname if one of category have deleted.
The most important question here is about the business logic. Does an order without a category make sense? If yes, then you can set the categoryId to null in the orders table when a category is deleted. You can use triggers for that.
However a better solution would be to add enabled column to your category and instead of deleting a category simply set its enabled to false - this makes it unavailable for further selection yet preserves the previous information/relationship. Of course, this would require a small change in the place where the categories are selected for presentation, namely adding where enabled=true to the query.
If you're set on deleting the category and settings category ID to null in the orders, then the syntax you're looking for is
DELIMITER //
CREATE TRIGGER category_before_delete
BEFORE DELETE ON category FOR EACH ROW
BEGIN
UPDATE `order` SET categoryid=null WHERE categoryid=OLD.categoryid;
END; //
DELIMITER ;
Related
I'm trying to make a blog system of sort and I ran into a slight problem.
Simply put, there's 3 columns in my article table:
id SERIAL,
category VARCHAR FK,
category_id INT
id column is obviously the PK and it is used as a global identifier for all articles.
category column is well .. category.
category_id is used as a UNIQUE ID within a category so currently there is a UNIQUE(category, category_id) constraint in place.
However, I also want for category_id to auto-increment.
I want it so that every time I execute a query like
INSERT INTO article(category) VALUES ('stackoverflow');
I want the category_id column to be automatically be filled according to the latest category_id of the 'stackoverflow' category.
Achieving this in my logic code is quite easy. I just select latest num and insert +1 of that but that involves two separate queries.
I am looking for a SQL solution that can do all this in one query.
This has been asked many times and the general idea is bound to fail in a multi-user environment - and a blog system sounds like exactly such a case.
So the best answer is: Don't. Consider a different approach.
Drop the column category_id completely from your table - it does not store any information the other two columns (id, category) wouldn't store already.
Your id is a serial column and already auto-increments in a reliable fashion.
Auto increment SQL function
If you need some kind of category_id without gaps per category, generate it on the fly with row_number():
Serial numbers per group of rows for compound key
Concept
There are at least several ways to approach this. First one that comes to my mind:
Assign a value for category_id column inside a trigger executed for each row, by overwriting the input value from INSERT statement.
Action
Here's the SQL Fiddle to see the code in action
For a simple test, I'm creating article table holding categories and their id's that should be unique for each category. I have omitted constraint creation - that's not relevant to present the point.
create table article ( id serial, category varchar, category_id int )
Inserting some values for two distinct categories using generate_series() function to have an auto-increment already in place.
insert into article(category, category_id)
select 'stackoverflow', i from generate_series(1,1) i
union all
select 'stackexchange', i from generate_series(1,3) i
Creating a trigger function, that would select MAX(category_id) and increment its value by 1 for a category we're inserting a row with and then overwrite the value right before moving on with the actual INSERT to table (BEFORE INSERT trigger takes care of that).
CREATE OR REPLACE FUNCTION category_increment()
RETURNS trigger
LANGUAGE plpgsql
AS
$$
DECLARE
v_category_inc int := 0;
BEGIN
SELECT MAX(category_id) + 1 INTO v_category_inc FROM article WHERE category = NEW.category;
IF v_category_inc is null THEN
NEW.category_id := 1;
ELSE
NEW.category_id := v_category_inc;
END IF;
RETURN NEW;
END;
$$
Using the function as a trigger.
CREATE TRIGGER trg_category_increment
BEFORE INSERT ON article
FOR EACH ROW EXECUTE PROCEDURE category_increment()
Inserting some more values (post trigger appliance) for already existing categories and non-existing ones.
INSERT INTO article(category) VALUES
('stackoverflow'),
('stackexchange'),
('nonexisting');
Query used to select data:
select category, category_id From article order by 1,2
Result for initial inserts:
category category_id
stackexchange 1
stackexchange 2
stackexchange 3
stackoverflow 1
Result after final inserts:
category category_id
nonexisting 1
stackexchange 1
stackexchange 2
stackexchange 3
stackexchange 4
stackoverflow 1
stackoverflow 2
Postgresql uses sequences to achieve this; it's a different approach from what you are used to in MySQL. Take a look at http://www.postgresql.org/docs/current/static/sql-createsequence.html for complete reference.
Basically you create a sequence (a database object) by:
CREATE SEQUENCE serials;
And then when you want to add to your table you will have:
INSERT INTO mytable (name, id) VALUES ('The Name', NEXTVAL('serials')
I'm trying to make a blog system of sort and I ran into a slight problem.
Simply put, there's 3 columns in my article table:
id SERIAL,
category VARCHAR FK,
category_id INT
id column is obviously the PK and it is used as a global identifier for all articles.
category column is well .. category.
category_id is used as a UNIQUE ID within a category so currently there is a UNIQUE(category, category_id) constraint in place.
However, I also want for category_id to auto-increment.
I want it so that every time I execute a query like
INSERT INTO article(category) VALUES ('stackoverflow');
I want the category_id column to be automatically be filled according to the latest category_id of the 'stackoverflow' category.
Achieving this in my logic code is quite easy. I just select latest num and insert +1 of that but that involves two separate queries.
I am looking for a SQL solution that can do all this in one query.
This has been asked many times and the general idea is bound to fail in a multi-user environment - and a blog system sounds like exactly such a case.
So the best answer is: Don't. Consider a different approach.
Drop the column category_id completely from your table - it does not store any information the other two columns (id, category) wouldn't store already.
Your id is a serial column and already auto-increments in a reliable fashion.
Auto increment SQL function
If you need some kind of category_id without gaps per category, generate it on the fly with row_number():
Serial numbers per group of rows for compound key
Concept
There are at least several ways to approach this. First one that comes to my mind:
Assign a value for category_id column inside a trigger executed for each row, by overwriting the input value from INSERT statement.
Action
Here's the SQL Fiddle to see the code in action
For a simple test, I'm creating article table holding categories and their id's that should be unique for each category. I have omitted constraint creation - that's not relevant to present the point.
create table article ( id serial, category varchar, category_id int )
Inserting some values for two distinct categories using generate_series() function to have an auto-increment already in place.
insert into article(category, category_id)
select 'stackoverflow', i from generate_series(1,1) i
union all
select 'stackexchange', i from generate_series(1,3) i
Creating a trigger function, that would select MAX(category_id) and increment its value by 1 for a category we're inserting a row with and then overwrite the value right before moving on with the actual INSERT to table (BEFORE INSERT trigger takes care of that).
CREATE OR REPLACE FUNCTION category_increment()
RETURNS trigger
LANGUAGE plpgsql
AS
$$
DECLARE
v_category_inc int := 0;
BEGIN
SELECT MAX(category_id) + 1 INTO v_category_inc FROM article WHERE category = NEW.category;
IF v_category_inc is null THEN
NEW.category_id := 1;
ELSE
NEW.category_id := v_category_inc;
END IF;
RETURN NEW;
END;
$$
Using the function as a trigger.
CREATE TRIGGER trg_category_increment
BEFORE INSERT ON article
FOR EACH ROW EXECUTE PROCEDURE category_increment()
Inserting some more values (post trigger appliance) for already existing categories and non-existing ones.
INSERT INTO article(category) VALUES
('stackoverflow'),
('stackexchange'),
('nonexisting');
Query used to select data:
select category, category_id From article order by 1,2
Result for initial inserts:
category category_id
stackexchange 1
stackexchange 2
stackexchange 3
stackoverflow 1
Result after final inserts:
category category_id
nonexisting 1
stackexchange 1
stackexchange 2
stackexchange 3
stackexchange 4
stackoverflow 1
stackoverflow 2
Postgresql uses sequences to achieve this; it's a different approach from what you are used to in MySQL. Take a look at http://www.postgresql.org/docs/current/static/sql-createsequence.html for complete reference.
Basically you create a sequence (a database object) by:
CREATE SEQUENCE serials;
And then when you want to add to your table you will have:
INSERT INTO mytable (name, id) VALUES ('The Name', NEXTVAL('serials')
I'm trying to make a blog system of sort and I ran into a slight problem.
Simply put, there's 3 columns in my article table:
id SERIAL,
category VARCHAR FK,
category_id INT
id column is obviously the PK and it is used as a global identifier for all articles.
category column is well .. category.
category_id is used as a UNIQUE ID within a category so currently there is a UNIQUE(category, category_id) constraint in place.
However, I also want for category_id to auto-increment.
I want it so that every time I execute a query like
INSERT INTO article(category) VALUES ('stackoverflow');
I want the category_id column to be automatically be filled according to the latest category_id of the 'stackoverflow' category.
Achieving this in my logic code is quite easy. I just select latest num and insert +1 of that but that involves two separate queries.
I am looking for a SQL solution that can do all this in one query.
This has been asked many times and the general idea is bound to fail in a multi-user environment - and a blog system sounds like exactly such a case.
So the best answer is: Don't. Consider a different approach.
Drop the column category_id completely from your table - it does not store any information the other two columns (id, category) wouldn't store already.
Your id is a serial column and already auto-increments in a reliable fashion.
Auto increment SQL function
If you need some kind of category_id without gaps per category, generate it on the fly with row_number():
Serial numbers per group of rows for compound key
Concept
There are at least several ways to approach this. First one that comes to my mind:
Assign a value for category_id column inside a trigger executed for each row, by overwriting the input value from INSERT statement.
Action
Here's the SQL Fiddle to see the code in action
For a simple test, I'm creating article table holding categories and their id's that should be unique for each category. I have omitted constraint creation - that's not relevant to present the point.
create table article ( id serial, category varchar, category_id int )
Inserting some values for two distinct categories using generate_series() function to have an auto-increment already in place.
insert into article(category, category_id)
select 'stackoverflow', i from generate_series(1,1) i
union all
select 'stackexchange', i from generate_series(1,3) i
Creating a trigger function, that would select MAX(category_id) and increment its value by 1 for a category we're inserting a row with and then overwrite the value right before moving on with the actual INSERT to table (BEFORE INSERT trigger takes care of that).
CREATE OR REPLACE FUNCTION category_increment()
RETURNS trigger
LANGUAGE plpgsql
AS
$$
DECLARE
v_category_inc int := 0;
BEGIN
SELECT MAX(category_id) + 1 INTO v_category_inc FROM article WHERE category = NEW.category;
IF v_category_inc is null THEN
NEW.category_id := 1;
ELSE
NEW.category_id := v_category_inc;
END IF;
RETURN NEW;
END;
$$
Using the function as a trigger.
CREATE TRIGGER trg_category_increment
BEFORE INSERT ON article
FOR EACH ROW EXECUTE PROCEDURE category_increment()
Inserting some more values (post trigger appliance) for already existing categories and non-existing ones.
INSERT INTO article(category) VALUES
('stackoverflow'),
('stackexchange'),
('nonexisting');
Query used to select data:
select category, category_id From article order by 1,2
Result for initial inserts:
category category_id
stackexchange 1
stackexchange 2
stackexchange 3
stackoverflow 1
Result after final inserts:
category category_id
nonexisting 1
stackexchange 1
stackexchange 2
stackexchange 3
stackexchange 4
stackoverflow 1
stackoverflow 2
Postgresql uses sequences to achieve this; it's a different approach from what you are used to in MySQL. Take a look at http://www.postgresql.org/docs/current/static/sql-createsequence.html for complete reference.
Basically you create a sequence (a database object) by:
CREATE SEQUENCE serials;
And then when you want to add to your table you will have:
INSERT INTO mytable (name, id) VALUES ('The Name', NEXTVAL('serials')
salesman
========
uId
salesGroupLinked
================
uId
groupId
//add performacesScore field here
group
======
groupId
I have 3 table above that formed many to many relationship, and I would add a field 'performaces' (INT) so that each salesman can have a score in each group. And I believe it should be located at salesGroupLinked table. But since uId and groupId is FK, I can't insert / edit the data (I'm using phpmyadmin). I can't make the performacesScore field unique since they can be same value for example a salesman get 10 and another get the same.
I got this msg :
This table does not contain a unique column. Grid edit, checkbox,
Edit, Copy and Delete features are not available.
describe salesGroupLinked
The tool is simply telling you that there can be several entries for a uId-groupId combination. Example:
uId groupId performacesScore
1 1 10
1 2 20
2 1 30
2 1 30
2 1 40
2 2 20
Now imagine this data is shown to you and you make the first 2/1/30 a 2/1/50. What update statement could the tool sent to the dbms?
update salesGroupLinked set performacesScore = 50
where uId = 2 and groupId = 1;
This would update three records instead of one.
update salesGroupLinked set performacesScore = 50
where uId = 2 and groupId = 1 and performacesScore = 30;
This would still update two records instead of one.
So in order to properly update and delete, you must tell the dbms what makes the records unique. There are four possibilities:
If you never want to update or delete single records, leave it as is.
If you want to be able to update and there can only be one entry for a uId-groupId combination, then tell the dbms so and make uId plus groupId the primary key of your table.
If you want to be able to update and there can be duplicates for a a uId-groupId combination, but a uId-groupId-performacesScore combination will always be unique, then make these three the table's primary key.
If you want to be able to update and there can be duplicates for any combination, then give the table another column for a technical id and make this the primary key.
Creating a mini-database with access, i came across this problem:
For the background, i have two tables:
Table: Items and Table: Actions
ID(PK) Name ID(PK) Name
------------------ ----------------
1 Thing1 1 Move
2 Thing2 2 Delete
3 Thing3
I created a query that lists available actions for each item:
Query: AvailableActions
Item_ID Action_ID
------------------------
1 2 //Thing1 can be deleted
2 1 //Thing2 can be moved
2 2 //Thing1 can be deleted
(no more records)
Now i want to populate a third table that lists the history of objects
Table: History
ID(PK) Item_ID Action_ID
----------------------------------
1 1 2
2 1 2
3 2 1
4 2 2
So i'm trying to make a lookup-field for Action_ID, where i can only pick values that are allowed for the choosed item. However, be it in design mode or SQL mode, i can't get the value of that field.
Do you have any hints?
Before you sort out the UI (mop the floor...), ensure you have the required constraint on the table (...fix the leak) e.g. ANSI-92 Query Mode SQL DDL:
ALTER TABLE History ADD
CONSTRAINT fk__history__AvailableActions
FOREIGN KEY (Item_ID, Action_ID)
REFERENCES AvailableActions (Item_ID, Action_ID);
...assuming you already have the required unique constraint on AvailableActions (Item_ID, Action_ID).
If you want a list of actions that can be applied to Item X then you can generate this with:
SELECT Actions.ID, Actions.Name FROM Actions INNER JOIN AvailableActions
ON Actions.ID = AvailableActions.ActionID WHERE Actions.Item_ID = X
When you talk about deleting "Thing 1", do you actually intend to delete the record from the table or does that record proxy for something else (like a disk file). If you actually delete it, you will have trouble establishing a PK / FK relationship between Items and AvailableActions if that was your intent.
Well as i stated in comments, the only way i achieved this goal is by adding a sub-form to the Items form. (unable to specify this with the structure only, as those Available_actions are computed depending on that same History table)