Sql 如何使用多个值更新列

Sql 如何使用多个值更新列,sql,oracle,Sql,Oracle,我是PLSQL的新手,我想知道如何用多个值更新列。例如,假设我有一个名为books的表,它有一个书名和书价,在开始时,我只有书“C#”的价格300。更新之后,我需要将300和400作为“C#”一书的价格 在同一列中使用多个值并用某些特定字符分隔,这绝不是一个好主意。该表应该规范化,或者我们可以添加一个新的可空列,如UpdatedPrice,并使用它,如: ALTER TABLE BOOK ADD COLUMN UpdatedPrice int GO UPDATE BOOK SET Update

我是PLSQL的新手,我想知道如何用多个值更新列。例如,假设我有一个名为books的表,它有一个书名和书价,在开始时,我只有书“C#”的价格300。更新之后,我需要将300和400作为“C#”一书的价格


在同一列中使用多个值并用某些特定字符分隔,这绝不是一个好主意。该表应该规范化,或者我们可以添加一个新的可空列,如UpdatedPrice,并使用它,如:

ALTER TABLE BOOK
ADD COLUMN UpdatedPrice int
GO

UPDATE BOOK
SET UpdatedPrice = 400
WHERE Book_Name = 'C#'

这样,您可以同时获得两种价格。在代码中,当UpdatedPrice为空时使用Price,否则使用UpdatedPrice,一切都会好起来。

创建一个触发器来保持以前的价格

CREATE OR REPLACE TRIGGER trig_book
   BEFORE UPDATE OF price
   ON book
   FOR EACH ROW
BEGIN
   :new.price := :old.price || ',' || :new.price;
END;

这只是创建存储过程的基本方法,您可以通过在更新后捕获错误代码来改进它。在oracle中缝合字符串的命令是| |

Create or Replace Procedure upd_Book_Price (in_book_name varchar(10), 
in_newprice varchar(10));
IS
BEGIN

Update Book
Set Price = Price || ',' || in_newprice
Where Book_Name = in_book_name;

Commit;

End;

我建议另一个-标准化-选项(我看到你问那会是什么?。有很多来源,这是怎么说的),一个包含这些书的所有价格的子表

虽然你可以把两个(或更多的价格)放在一列中,但相信我们——这是一个糟糕的选择

考虑使用类似的方法:

SQL> create table book
  2    (isbn   varchar2(13) primary key,
  3     name   varchar2(20) not null
  4    );

Table created.

SQL> create table price
  2    (id        number primary key,
  3     isbn      varchar2(13) constraint fk_pr_boo references book (isbn),
  4     date_from date not null,
  5     price     number
  6    );

Table created.

SQL>
SQL> insert all
  2    into book (isbn, name) values ('1-1234-124', 'C#')
  3    into book (isbn, name) values ('9-1244-332', 'C++')
  4    --
  5    into price (id, isbn, date_From, price) values (1, '1-1234-124', date '2018-01-01', 300)
  6    into price (id, isbn, date_From, price) values (2, '1-1234-124', date '2018-03-20', 400)
  7  select * From dual;

4 rows created.

SQL>
SQL> select b.isbn, b.name, p.date_from, p.price
  2  from book b left join price p on p.isbn = b.isbn
  3  order by b.isbn, p.date_from;

ISBN          NAME                 DATE_FROM       PRICE
------------- -------------------- ---------- ----------
1-1234-124    C#                   01.01.2018        300
1-1234-124    C#                   20.03.2018        400
9-1244-332    C++

SQL>
Book_Name| Price
---------|--------
C#       | ,400

正如其他人已经提到的,在一列中共享多个值是不好的做法。如果您确实需要一种产品(书籍)的多种价格,有几种可能的选择: 制作两张表格: 表1:

这样,一个产品可以有多个价格,只需将产品名称保存在一行,而不是多行

第二种方法是使用关系表:

create table products
(  id number(5),
   name VARCHAR2(20 CHAR)
);
/
create table prices
(  id number(5),
   value number(6,2),
   product_id number(5)
)
/
create table product_price
(  product_id number(5),
   price_id number(5),
   FOREIGN KEY (product_id)
        REFERENCES products(id) NOT NULL,
   FOREIGN KEY (price_id)
        REFERENCES prices(id) NOT NULL
)
/
insert into products values(1, 'C#');
insert into products values(1, 'C++');

insert into prices values(1, 300);
insert into prices values(2, 400);
insert into prices values(3, 700);

insert into product_price values(1, 1);
insert into product_price values(1, 2);
insert into product_price values(2, 3);
在一列中存储多个值总是一个坏主意,因为这会使读取数据变得非常困难,并带来各种其他问题(如何更新包含的4个值中的一个值?)

始终尝试在数据库中只保存每个值一次(即产品名称“C”)。并寻找最适合您的解决方案的方法。如果你总是得到只适合一种产品的多个价格,我会选择第一种方法,有两个表。如果有多个价格匹配多个产品,我会选择关系表

如果您只想在更新列之前保存上一个价格,请编写触发器将其保存到日志表:

create trigger tu_tablename --tu = triggerUpdate
before insert on tablename
for each row
begin
   --writes the values before the insert to the log table
   insert into logTable values (:old.name, :old.price, sysdate);
   --logTable has columns product_name, old_price_value and date_change
end;
/

(请原谅可能出现的语法错误,将其视为挑战)

数据库表中的列有一个数据类型,并且应该有一个值。尽管如果你真的想这样做,你可以在更新时使用连接,像这样添加到任何已经存在的字符中(不需要PL/SQL,只需要普通SQL):

顺便说一句,如果一本书没有价格,而你做了这个更新,它最终会变成这样:

SQL> create table book
  2    (isbn   varchar2(13) primary key,
  3     name   varchar2(20) not null
  4    );

Table created.

SQL> create table price
  2    (id        number primary key,
  3     isbn      varchar2(13) constraint fk_pr_boo references book (isbn),
  4     date_from date not null,
  5     price     number
  6    );

Table created.

SQL>
SQL> insert all
  2    into book (isbn, name) values ('1-1234-124', 'C#')
  3    into book (isbn, name) values ('9-1244-332', 'C++')
  4    --
  5    into price (id, isbn, date_From, price) values (1, '1-1234-124', date '2018-01-01', 300)
  6    into price (id, isbn, date_From, price) values (2, '1-1234-124', date '2018-03-20', 400)
  7  select * From dual;

4 rows created.

SQL>
SQL> select b.isbn, b.name, p.date_from, p.price
  2  from book b left join price p on p.isbn = b.isbn
  3  order by b.isbn, p.date_from;

ISBN          NAME                 DATE_FROM       PRICE
------------- -------------------- ---------- ----------
1-1234-124    C#                   01.01.2018        300
1-1234-124    C#                   20.03.2018        400
9-1244-332    C++

SQL>
Book_Name| Price
---------|--------
C#       | ,400
要防止出现这种情况,请添加一个大小写,以便在其中已有其他值时不包含逗号:

UPDATE Book set Price = 
CASE WHEN Price IS NOT NULL 
THEN Price || ', '|| '400' 
else '400'
end
where Book_Name = 'C#' ; 
然而,这种设计不是很好。这意味着在字符数据类型的列中,您已经放置了隐藏在其中的数字

最好是有多个列:

Book_Name| Price1   | Price2
---------|----------|--------
C#       | 300      |   400
C++      | 500      |   600
Java     | 700      |   800
以上是罚款,如果你知道不同的价格,你将有多少。这取决于您试图解决的问题,取决于业务逻辑。但是,如果您不知道可能的价格的最大数量,那么为每本书设置一个二级价格表是有意义的(您需要为每本书设置一个不同的ID,根据该ID,另一个表将有一个其所有价格的列表),或者可以这样更改现有表:

    Book_Name| Prices   
    ---------|----------
    C#       | 300 
    C#       | 400
    C++      | 500      
    C++      | 600      
    Java     | 700      
    Java     | 800
在这种情况下,您不必进行更新,而是每次插入新行:

INSERT INTO Book (Book_Name, Price) VALUES ( 'C#', 400) ;
INSERT INTO Book (Book_Name, Price) VALUES ( 'C++', 600) ;
INSERT INTO Book (Book_Name, Price) VALUES ( 'Java', 800) ;

@kc2018这行不通,因为我需要更新我已经拥有的varray的price列中的值。你应该规范化你的table@Triple3XH阅读一些数据库设计书籍。你的设计会带来灾难。最好现在就修改你的设计,而不是以后。他说的triple3xh是指你的书表应该有Id、标题、作者、主题等信息。如果你的书的属性可以是0多个值,你应该有一个相关的查找表,例如“BookPrices”和Id、book\u Id、Price列,该书的每个价格可能都有一个条目。此表将替换book表中逗号分隔的列。请勿在一列中存储多个逗号分隔的值。这会给你带来很多问题,这只是一个开始。对于所有的答案,我知道这不是一个好的做法,但这是任务的要求
INSERT INTO Book (Book_Name, Price) VALUES ( 'C#', 400) ;
INSERT INTO Book (Book_Name, Price) VALUES ( 'C++', 600) ;
INSERT INTO Book (Book_Name, Price) VALUES ( 'Java', 800) ;