Di Chuyển Dữ Liệu Qua Bảng Khác

Vũ Huy Tâm

Khi cần chuyển các bản ghi từ một bảng này sang một bảng khác, bạn có hai cách làm: dùng lệnh INSERT INTO … SELECT FROM…; hoặc dùng SELECT INTO…FROM… Mỗi cách có ưu điểm và nhược điểm riêng, cũng như có phạm vi ứng dụng nhất định. Khi lượng dữ liệu cần di chuyển càng lớn thì sự khác biệt giữa hai cách làm càng rõ.

Cách 1

SELECT Cot1, Cot2, Cot3
INTO Bang2
FROM Bang1

Kết quả của câu lệnh này là bảng Bang2 được tạo ra và chứa các bản ghi của bảng Bang1. Nếu Bang2 đã tồn tại, lệnh sẽ báo lỗi và dừng. Các cột được tạo trong Bang2 sẽ có kiểu dữ liệu copy từ cột tương ứng trong Bang1. Trong trường hợp bạn muốn đổi kiểu dữ liệu, bạn có thể dùng hàm CAST:

SELECT Cot1, Cot2, CAST(Cot3 AS INT) AS Cot3
INTO Bang2
FROM Bang1

Bang2 được tạo ra cũng “trần trụi” – không có khóa chính, index, identity… các cột cũng luôn là cho phép NULL.
Ưu điểm lớn nhất của phương pháp này là nó có tốc độ thực hiện rất nhanh. Nó không phải ghi vào transaction log (và do đó không rollback được) vì thế việc thực thi của nó rất gọn nhẹ. Ở các phiên bản SQL Server cũ (2000 trở về trước), phương pháp này đòi hỏi khóa (lock) vào toàn bộ cấu trúc của database. Vì thế trong thời gian câu lệnh thực thi, các connection khác không thực hiện được các lệnh thay đổi schema (sửa bảng, tạo index…). Điều này đã không còn đúng nữa ở các phiên bản gần đây hơn (hình như từ bản 2000 Service Pack 4). Đây là điều mà khá nhiều người vẫn lầm tưởng và hạn chế sử dụng phương pháp này.
Tuy nhiên phương pháp này đòi hỏi phải tạo bảng mới, nên bạn không thể dùng nếu muốn insert thêm dữ liệu vào bảng đã có sẵn. Đồng thời việc tạo bảng mới cũng làm mất tính ổn định của schema (schema instability). Trong môi trường production đây là nhược điểm lớn nhất, đặc biệt bạn không thể dùng cho các tính năng mà nhiều người cùng sử dụng (ví dụ hai người đồng thời dùng một tính năng ở website dẫn đến câu lệnh này được gọi, lần gọi sau sẽ báo lỗi vì Bang2 đã tồn tại).
Phương pháp này thích hợp với các tác vụ ad hoc hoặc chạy theo batch và không có giao tiếp với người dùng. Khi đó thường dữ liệu cần xử lý với lượng lớn và đây chính là yếu tố mà phương pháp này phát huy hiệu quả.

Cách 2

INSERT INTO Bang2(Cot1, Cot2, Cot3)
SELECT Cot1, Cot2, Cot3
FROM Bang1

Đây là cách làm mà có lẽ nhiều người cho là mẫu mực và an toàn. Nó đòi hỏi bảng Bang2 phải tồn tại sẵn và có cấu trúc phù hợp với các trường trong lệnh SELECT. Vì Bang2 cần được tạo từ trước nên khi tạo bảng bạn có thể định nghĩa khóa, index, identity…
Phương pháp này cho phép nhiều người dùng cùng thực hiện, không gây xáo trộn schema, và có thể rollback khi nằm trong 1 transaction do nó dùng transaction log. Vì thế ở các hệ thống giao dịch với người dùng đây là cách bạn nên áp dụng.
Tuy nhiên nhược điểm của phương pháp này là do nó dùng transaction log nên khi áp dụng với lượng dữ liệu lớn nó thực hiện rất chậm.




Tags: ,

22 Comments
Posted on 7/3/2012 | Categories: SQL Server Programming

Các bài viết tương tự

Comments
  • SQL Beginer (11/03/2012 10:59 am)

    Chào bạn.
    Cảm ơn bạn với bài viết rất hữu ích. Cho mình hỏi thêm. Nếu mình chỉ muốn chuyển các dữ liệu từ bảng này tới bảng khác với các dữ liệu có điều kiện thì làm thế nào?
    Xin cảm ơn

    • PhuocHanTien (12/03/2012 9:08 pm)

      Đối với các dữ liệu có điều kiện thì điều kiện bạn đặt ở câu Select(có nghĩa là: Lấy dữ liệu theo điều kiện rồi đưa vào bảng khác)

      SELECT Cot1, Cot2, Cot3
          INTO Bang2
          FROM Bang1
          WHERE ....
       
       
      INSERT INTO Bang2(Cot1, Cot2, Cot3)
          SELECT Cot1, Cot2, Cot3
          FROM Bang1
          WHERE.....
  • Magicgreen (15/04/2012 3:08 pm)

    em muốn tạo 1 procedure sử dụng cách 2 của anh thì làm ntn ạ. em muốn sao dữ liệu từ bảng HOPDONG sang bảng THANHTOAN
    em làm theo thì bị báo lỗi : com.microsoft.sqlserver.jdbc.SQLServerException: The statement did not return a result set.

    ALTER PROC [dbo].[spInsert1]

    AS

    SET IDENTITY_INSERT dbo.THANHTOAN ON
    INSERT INTO THANHTOAN(maHopDong,maPhong,kieuPhong,maKhach,hoTen,diaChi,
    soDienThoai,soChungMinhThu,
    ngayThue)
    SELECT maHopDong,maPhong,kieuPhong,maKhach,hoTen,diaChi,
    soDienThoai,soChungMinhThu,
    ngayThue
    FROM HOPDONG

    BEGIN
    SELECT * FROM THANHTOAN

    END

    bây giờ em phải sửa ntn ạ

    • Vũ Huy Tâm (17/04/2012 12:40 pm)

      Đoạn lệnh của bạn buồn cười quá. Vậy là mỗi lần gọi thủ tục thì nó lại insert vào bảng thanhtoan hay sao? Ngoài ra BEGIN và END phải bao toàn bộ đoạn code của thủ tục. Bạn sửa lại xem có còn bị lỗi không

  • Lê Hưng (15/11/2012 9:45 pm)

    tham khảo đây thử
    http://msdn.microsoft.com/en-us/library/aa258255(v=sql.80).aspx

  • Nguyễn Văn An (22/11/2012 6:35 am)

    Xin Chào !
    Tôi đang gặp rắc rối với SQL. Làm sao để update dữ liệu từ table của data này sang table của 1 data khác.
    Vi dụ: Trong Databa BD co bang TD1 trong bảng này có cột Dien tich, so hieu to, so hieu thua
    Và trong Databa BD co bang TDat trong bảng này có cột Dien tich, so hieu to, so hieu thua
    Tôi muốn update cọt dien tich của TD1 vao Tdat
    xin anh em chỉ dùm
    Cám ơn nhiều!

  • Vủ (28/11/2012 1:25 pm)

    Chào !!!

    tôi đang gặp rắc rối về copy dữ liệu, mong được sự giúp đỡ.
    giả sử có 1 bảng là KhungCT có 3 cột MaKhung, TenKhung,Khoa.VD ở cột Khoá giá trị là 5(nó gồm nhiều dòng dữ liệu).
    Tôi muốn copy tất cả các dòng mà có cột Khoa là 5 vào trong bảng đó luôn, và thay đổi giá trị Khoá thành 6.

    Thank

  • Tuyen Nguyen (29/08/2013 11:10 pm)

    Cám ơn bạn về bài viết hữu ích nhá.. :) chúc bạn sức khỏe và thành công.

    • Nhanvvqsqn (06/11/2013 8:23 pm)

      Xin chào mọi người,

      Mình có khó khăn trong cách thiết kế CSDL để áp dụng trong chương trình SPC tự động.
      Có khoảng vài trăm máy chạy vài trăm Part khác nhau, dữ liệu 1 ngày có thể lên đến vài nghìn record.
      Mỗi máy tương ứng với 1 part sẽ áp dụng 1 form đo, mỗi lần đo phải truy xuất dữ liệu liên quan trước đây.
      Theo mình nghĩ thì khi dữ liệu tăng lên thì tốc độ truy xuất sẽ chậm, các bạn có kinh nghiệm chia sẽ giúp mình 1 cơ chế nào đó giúp tăng tốc độ truy xuất khi dữ liệu tăng.
      Chẳng hạn như khi dữ liệu lên 1 năm mà khi truy xuất mình chỉ cho truy xuất 1 quý thôi cũng được.
      Hiện mình đang dùng Visual Studio 2008 và CSDL là accdb.
      Muốn chuyển sang SQL server để lưu được dữ liệu nhiều hơn.
      Rất mong nhận được sự quan tâm và giúp đỡ của các bạn.

      Than

  • hung (19/11/2013 10:20 am)

    Mấy anh oi cho em hỏi là hiện giờ em sử dụng một bảng dữ liệu sqlite để kiểm tra dữ liệu khi dùng máy quét thẻ Rfid thì em phải viết câu truy vấn như thế nào để kiểm tra dữ liệu bên dưới dữ liệu đã có dữ liệu hay chưa?
    -Nếu dữ liệu đã có thì báo “true” và “update” dữ liệu đó vào bảng
    -Nếu dữ liệu chưa có thì báo là “false” và “insert” dữ liệu vào bảng

  • Tuyen Nguyen (04/12/2013 10:08 pm)

    Tiện đây cho mình hỏi, nếu trong 1 table, mình lấy dữ liệu từ 1 cột, update qua một cột khác có điều kiện, thì làm thế nào hả mọi người..

    • Tran nguyen khanh (09/12/2013 4:22 am)

      insert into table
      select * from database.dbo.table where ….
      or
      insert into table(…)
      select (…) from database.dbo.table where ….

  • Thanh Le Cong (21/02/2014 11:41 pm)

    Bạn cho mình góp ý cái nhé “Bang2 được tạo ra cũng “trần trụi” – không có khóa chính, index, identity” câu này bạn đã chứng mình chưa ? Thực tế khi mình đang làm là bị tình trạng bản Into (mà ví dụ là bang2) nó vẫn tồn tại Identity. Không biết là do mình làm gì sai hay là vốn dĩ nó vẫn giữ thuộc tính cũ của bảng gốc ?

    • Vũ Huy Tâm (24/02/2014 1:07 pm)

      Vâng mình sơ suất, thuộc tính identity vẫn được tạo trong bảng mới, nhưng index và khóa chính (nói chung các ràng buộc) không được tạo

  • Duyên (27/03/2014 5:57 am)

    cho mình hỏi cái này với
    /* kiểm tra xem có lần quan trắc nào mà ngày nhập liệu trước ngày đo không. nếu có cập nhập ngày nhập liệu = ngày đo */
    if ((select DAY(NgayDo) from ThongTinQuanTrac)-(select DAY(NgayNhapLieu) from ThongTinQuanTrac))>0
    begin
    print ‘có trạm quan trắc ngày đo trước ngày nhập liệu’
    select TramQuanTrac.MaTQT,TramQuanTrac.TenTQT,ThongTinQuanTrac.MaTTQT,ThongTinQuanTrac.NgayDo,ThongTinQuanTrac.NgayNhapLieu
    from TramQuanTrac,ThongTinQuanTrac,QuanTrac
    where TramQuanTrac.MaTQT=QuanTrac.MaTQT
    and ThongTinQuanTrac.MaTTQT=QuanTrac.MaTTQT
    and DAY(NgayDo)> DAY(NgayNhapLieu)
    update ThongTinQuanTrac
    set NgayNhapLieu=NgayDo
    where DAY(NgayDo)> DAY(NgayNhapLieu)
    end
    ELSE

    LỖI XẢY RA VÌ CÓ RẤT NHIỀU GIÁ TRỊ NGÀY,cho mình hỏi câu lệnh nào để so sánh từng giá trị ngày đo với giá trị ngày nhập liệu với
    cảm ơn mọi người nhiều

  • Xuân Thành (17/07/2015 5:16 am)

    Chào anh/chị cho em hỏi một vấn đề ạ, em có một câu lệnh query sau khi thực hiện câu lệnh xong , nó trả về một bảng có 2 cột, em muốn lấy toàn bộ dữ liệu cột thứ 2 này cho vào một cột của một bảng đã tạo sẵn, có cùng hiểu dữ liệu thì làm thế nào ạ. Mà cái cột thứ 2 trả về từ câu lệnh query nó không có tên ạ

    • Banhxe0 (21/07/2015 6:33 am)

      Table1(col1,col2) — bảng bạn trả về.

      Insert Into BẩngMuonchen(column muốn chèn )
      Select Col2 from Table1.

  • CaoSax (04/09/2015 4:13 am)

    Chào cả nhà!
    Em có một vần đề nhỏ viết câu lệnh trong SQL cả nhà giúp em nha!
    VD: tbl_MH (MaMH, MatHang, DonGia)
    tbl_Gia (MaMH, SoLuong, GiaThiTruong)

    Em muốn cập nhật DonGia. Nếu MaMH của tbl_MH bằng MaMH của tbl_Gia thì lấy GiaThiTruong gán vào DonGia.

    Em cám ơn. :)

  • Sao Trực Tuyến (10/09/2016 10:14 am)

    Good replies in return of this issue with firm
    arguments and telling all regarding that.

  • Philophuong (03/11/2017 10:56 am)

    Chào bạn,

    Cảm ơn bạn rất nhiều. Đoạn lệnh rất ngắn nhưng đã giúp tôi giải quyết được bài toán bấy lâu nay!

  • PI TIPO (21/11/2017 1:28 am)

    mình mới hc nên k hiểu cho lắm trong cách 2 bạn chỉ thì là chép từ bảng 1 qua bảng 2 pải k

Leave a Reply to Vũ Huy Tâm

Click here to cancel reply.
Hướng dẫn: Để nhập mã T-SQL bạn dùng thẻ <pre lang="tsql"> và </pre>.
Ví dụ: <pre lang="tsql">SELECT * FROM MyTable</pre>