Cơ sở dữ liệu, bảng, chuẩn hóa và một kế hoạch sao lưu chắc chắn cho phép chúng tôi lưu trữ và duy trì dữ liệu.
Đến lượt mình, các phương pháp hay nhất kết hợp đó lại cho phép chúng tôi tương tác với dữ liệu đó. Trong thế giới dựa trên dữ liệu ngày nay, dữ liệu rất có giá trị. Không chỉ có giá trị, dữ liệu thường rất quan trọng đối với các giải pháp dành cho người dùng cuối được cung cấp bởi các sản phẩm và dịch vụ. Trích xuất thông tin chi tiết, trả lời câu hỏi và các số liệu có ý nghĩa từ dữ liệu bằng cách truy vấn và thao tác dữ liệu là một thành phần không thể thiếu của SQL nói chung.
PostgreSQL cũng không khác.
Điểm mấu chốt cơ bản này rất quan trọng để thành công trong bất kỳ khía cạnh nào theo hướng dữ liệu.
Dưới đây, tôi trình bày sự kết hợp của 8 truy vấn hoặc loại truy vấn khác nhau mà tôi thấy thú vị và hấp dẫn để khám phá, nghiên cứu, tìm hiểu hoặc thao tác các tập dữ liệu.
Chúng không được liệt kê theo bất kỳ thứ tự quan trọng nào.
Hầu hết có lẽ sẽ là những người bạn cũ quen thuộc. Có lẽ một số sẽ trở thành những người quen mới.
Các bảng và dữ liệu mẫu được sử dụng không quan trọng bằng việc xây dựng thực tế bản thân các truy vấn và những gì mỗi truy vấn trả về, cung cấp hoặc cung cấp. Nhiều người trong số họ là giả và có nguồn gốc cho mục đích trình diễn và không nên được hiểu theo nghĩa đen về giá trị của chúng.
1. Tham gia bên trái, lưu ý bất kỳ khoảng trống nào ở bên phải ...
Giả sử trong ví dụ này, chúng tôi có một đợt giảm giá đang diễn ra trong hai tháng và đang nhận được tổng cộng cả hai.
Tuy nhiên, vì một số lý do, tháng thứ hai không kéo được trọng lượng của nó và chúng tôi muốn nhắm mục tiêu những ngày nào trong tháng một sẽ tăng cân.
Những lần bán hàng này được biểu thị dưới dạng thanh toán qua bảng và fake_month cho cuộc trình diễn này.
Cần lưu ý:
- Chúng tôi sẽ chỉ kiểm tra các tổng lớn hơn 2000.
- Chúng tôi sẽ giới hạn đầu ra chỉ ở 10 hàng.
Để bắt đầu, chúng tôi có Biểu thức Bảng Chung (CTE) này ' tạo 'bảng fake_month cho chúng tôi và truy vấn sau đó.
dvdrental=> WITH fake_month AS(
SELECT setup::date
FROM generate_series('2007-02-01', '2007-02-28', INTERVAL '1 day') AS setup
)
SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
LIMIT 10;
legit | sum | fake
-------+---------+------
1 | 2808.24 | 1
2 | 2550.05 | 2
6 | 2077.14 | 6
8 | 2227.84 | 8
9 | 2067.86 | 9
17 | 3630.33 | 17
18 | 3977.74 | 18
19 | 3908.59 | 19
20 | 3888.98 | 20
21 | 3786.14 | 21
(10 rows)
Có vẻ như cả hai tháng đều đóng góp ở đó. Vậy điều này có được giải quyết không?
Trước khi chúng tôi xem điều này đã được giải quyết, hãy truy cập điều khoản ORDER BY.
Tất nhiên, bạn có thể ĐẶT HÀNG BẰNG ASC hoặc DESC.
Tuy nhiên, bạn cũng có thể ĐẶT HÀNG THEO NULL trước hoặc cuối cùng và điều đó sẽ thay đổi một chút.
Hãy viết lại truy vấn này và sử dụng ORDER BY NULLS trước trên cột hợp pháp.
Để ngắn gọn, tôi sẽ xóa CTE khỏi đầu ra, chỉ cần biết rằng nó vẫn ở đó và đang được sử dụng.
SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
ORDER BY legit NULLS first
LIMIT 10;
legit | sum | fake
-------+---------+------
1 | 2808.24 | 1
2 | 2550.05 | 2
6 | 2077.14 | 6
8 | 2227.84 | 8
9 | 2067.86 | 9
17 | 3630.33 | 17
18 | 3977.74 | 18
19 | 3908.59 | 19
20 | 3888.98 | 20
21 | 3786.14 | 21
(10 rows)
Không có gì khác biệt ở đó cả.
Điều gì sẽ xảy ra nếu chúng ta ĐẶT HÀNG BẰNG NULLS đầu tiên trên cột giả mạo? Cái ở bên phải bên của THAM GIA?
Hãy xem.
SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
ORDER BY fake NULLS first
LIMIT 10;
legit | sum | fake
-------+---------+------
29 | 2717.60 |
30 | 5723.89 |
1 | 2808.24 | 1
2 | 2550.05 | 2
6 | 2077.14 | 6
8 | 2227.84 | 8
9 | 2067.86 | 9
17 | 3630.33 | 17
18 | 3977.74 | 18
19 | 3908.59 | 19
(10 rows)
Bây giờ chúng tôi đang nhận được ở đâu đó. Chúng ta có thể thấy trong ngày 29 &30, cột giả đã được sắp xếp từ trên cùng của tập kết quả.
Do ĐẶT HÀNG BẰNG NULLS giả trước.
Điều này giải quyết được câu hỏi của chúng tôi, 'đợt giảm giá 2' bị trì hoãn vào những ngày nào.
Bạn đang thắc mắc ...
" Chúng tôi có thể chỉ lọc bằng WHERE fake IS NULL không? "
Như thế này:
SELECT date_part('day', p.payment_date)::INT AS legit,
SUM(p.amount),
date_part('day', fk.setup)::INT AS fake
FROM payment AS p
LEFT JOIN fake_month AS fk
ON date_part('day', fk.setup)::INT = date_part('day', p.payment_date)::INT
WHERE date_part('day', fk.setup) IS NULL
GROUP BY legit, fake
HAVING SUM(p.amount) > 2000
LIMIT 10;
legit | sum | fake
-------+---------+------
29 | 2717.60 |
30 | 5723.89 |
(2 rows)
Có mà hoạt động. Vì vậy, tại sao không chỉ sử dụng truy vấn đó thay thế? Tại sao nó lại quan trọng?
Tôi cảm thấy việc sử dụng LEFT JOIN và ORDER BY NULLS trước tiên cho bảng ở phía bên phải của JOIN, là một cách tuyệt vời để khám phá các bảng và tập dữ liệu không quen thuộc.
Bằng cách xác nhận những gì, nếu có, dữ liệu bị ‘ thiếu 'Ở phía đó của điều kiện tham gia đầu tiên; nâng cao sự rõ ràng và nhận thức, cho phép bạn sau đó lọc ra các kết quả được đặt với mệnh đề WHERE
Tất nhiên, việc quen thuộc với các bảng và tập dữ liệu có thể loại bỏ nhu cầu về LEFT JOIN được trình bày ở đây.
Đó là một truy vấn xứng đáng cho bất kỳ ai sử dụng PostgreSQL ít nhất phải thử trong quá trình khám phá.
2. Nối chuỗi
Nối, nối hoặc nối hai chuỗi, cung cấp một tùy chọn trình bày cho các tập kết quả. Nhiều ' điều 'có thể được nối.
Tuy nhiên, như đã lưu ý trong tài liệu, toán tử nối chuỗi ('||') chấp nhận đầu vào không phải là chuỗi, miễn là một là chuỗi.
Hãy 'xem một số ví dụ với các truy vấn dưới đây:
postgres=> SELECT 2||' times'||' 2 equals: '|| 2*2;
?column?
---------------------
2 times 2 equals: 4
(1 row)
Chúng ta có thể thấy, tất cả các số và chuỗi đều có thể được nối với nhau như đã đề cập ở trên.
Dấu '||' chỉ là một trong những toán tử có sẵn trong PostgreSQL.
Hàm concat () chấp nhận nhiều đối số, kết hợp tất cả lại với nhau.
Dưới đây là một ví dụ về chức năng đó đang hoạt động:
postgres=> SELECT concat('Josh ','Otwell') AS first_name;
first_name
-------------
Josh Otwell
(1 row)
Chúng ta có thể chuyển nhiều hơn hai đối số nếu muốn:
postgres=> SELECT concat('Josh',' ','Otwell') AS first_name;
first_name
-------------
Josh Otwell
(1 row)
Hãy ghi nhận một số điều thực sự nhanh chóng với các ví dụ tiếp theo sau:
postgres=> SELECT CONCAT('Josh',NULL,'Otwell') AS first_name;
first_name
------------
JoshOtwell
(1 row)
postgres=> SELECT 'Josh '||NULL||'Otwell' AS first_name;
first_name
------------
(1 row)
postgres=> SELECT NULL||'Josh '||'Otwell' AS first_name;
first_name
------------
(1 row)
postgres=> SELECT CONCAT(NULL,'Josh','Otwell') AS first_name;
first_name
------------
JoshOtwell
(1 row)
Quan sát rằng hàm concat () bỏ qua NULL bất kể được đặt ở đâu trong danh sách tham số, trong khi toán tử nối chuỗi thì không.
NULL được trả về nếu có ở bất kỳ đâu trong chuỗi để nối.
Chỉ cần lưu ý điều đó.
Thay vì đưa vào chuỗi được nối theo cách thủ công, PostgreSQL cũng bao gồm một hàm concat_ws () chấp nhận dấu phân tách chuỗi làm tham số đầu tiên.
Chúng tôi sẽ ghé thăm nó với các truy vấn sau:
postgres=> SELECT concat_ws('-',333,454,1919) AS cell_num;
cell_num
--------------
333-454-1919
(1 row)
postgres=> SELECT concat_ws(' ','Josh','Otwell') AS first_name;
first_name
-------------
Josh Otwell
(1 row)
concat_ws () chấp nhận số hoặc chuỗi làm đối số và như đã nêu ở trên, sử dụng đối số đầu tiên làm dấu phân tách.
Concat_ws () xử lý NULL như thế nào?
postgres=> SELECT concat_ws('-',333,NULL,1919) AS cell_num;
cell_num
----------
333-1919
(1 row)
postgres=> SELECT concat_ws(NULL,333,454,1919) AS cell_num;
cell_num
----------
(1 row)
NULL bị bỏ qua trừ khi nó là đối số phân tách được cung cấp cho concat_ws ().
Sau đó, tất cả các đối số bị bỏ qua và NULL được trả về thay thế.
Kết nối thật tuyệt ...
Bây giờ chúng ta đã có ý tưởng về cách hoạt động của nối, hãy xem một vài ví dụ về nó.
Quay lại cơ sở dữ liệu cho thuê DVD giả
Giả sử chúng ta cần lập danh sách họ và tên khách hàng, cùng với địa chỉ email của họ để gửi thư báo cập nhật tài khoản của họ.
Tôi sẽ giới hạn đầu ra chỉ 10 hàng vì lợi ích ngắn gọn, nhưng vẫn thể hiện || nhà điều hành.
dvdrental=> SELECT first_name||' '||last_name||'''s email address is: '||email AS name_and_email
FROM customer
LIMIT 10;
name_and_email
--------------------------------------------------------------------------
Jared Ely's email address is: [email protected]
Mary Smith's email address is: [email protected]
Patricia Johnson's email address is: [email protected]
Linda Williams's email address is: [email protected]
Barbara Jones's email address is: [email protected]
Elizabeth Brown's email address is: [email protected]
Jennifer Davis's email address is: [email protected]
Maria Miller's email address is: [email protected]
Susan Wilson's email address is: [email protected]
Margaret Moore's email address is: [email protected]
(10 rows)
Lưu ý rằng chúng tôi phải loại bỏ một trích dẫn duy nhất được sử dụng với dấu nháy đơn, sử dụng một trích dẫn duy nhất bổ sung để thể hiện quyền sở hữu địa chỉ email của mỗi khách hàng.
Tại sao bạn nên biết?
Đôi khi, việc kết hợp dữ liệu mang lại cho bạn cái nhìn sâu sắc hơn và hiểu rõ hơn về tập dữ liệu mà bạn đang làm việc. Cùng với các tùy chọn báo cáo, việc nối các tập dữ liệu được chia sẻ với những tập dữ liệu khác có thể làm cho chúng (dữ liệu) dễ đọc và dễ tiêu hóa hơn.
3. Cung cấp danh sách giá trị IN Với truy vấn con
Truy vấn con có nhiều công dụng mạnh mẽ. Trong số đó, việc cung cấp danh sách IN các giá trị để kiểm tra tư cách thành viên là một việc phổ biến.
Đây là cách sử dụng nhanh.
Giả sử chúng ta có bảng khách hàng và bảng thanh toán trong một cửa hàng cho thuê DVD giả và muốn thưởng cho năm khách hàng chi tiêu cao nhất đã thuê phim trong các ngày từ 10 - 13 tháng 4.
Hãy tưởng tượng đó là một khoảng thời gian mục tiêu đặc biệt. Vì vậy, nếu khách hàng đã chi hơn $ 30, chúng tôi muốn ghi nhận họ.
Hãy nhớ rằng, có các tùy chọn khả dụng khác để giải quyết loại câu hỏi này (tức là kết hợp, thu thập kết quả từ nhiều lựa chọn, v.v.), tuy nhiên, các truy vấn phụ cũng có thể xử lý nó.
Chúng tôi sẽ bắt đầu với toàn bộ shebang ở đây. Truy vấn hoàn chỉnh này trả về mọi thứ chúng tôi muốn cho câu hỏi cụ thể này.
dvdrental=> SELECT first_name, last_name, email
FROM customer
WHERE customer_id IN (
SELECT customer_id FROM (
SELECT DISTINCT customer_id, SUM(amount)
FROM payment
WHERE extract(month from payment_date) = 4
AND extract(day from payment_date) BETWEEN 10 AND 13
GROUP BY customer_id
HAVING SUM(amount) > 30
ORDER BY SUM(amount) DESC
LIMIT 5) AS top_five);
Ví dụ này thực sự chứa các truy vấn con lồng nhau, một trong số đó là Bảng gốc.
Hãy bắt đầu bằng cách đi sâu vào truy vấn con trong cùng, Bảng gốc đó.
Truy vấn con này là một câu lệnh SELECT độc lập, trả về một customer_id và một SUM () trên cột số tiền.
Chỉ những khách hàng đáp ứng các tiêu chí được kiểm tra bởi các điều khoản WHERE và HAVING mới thực hiện cắt giảm, được làm mỏng thêm với GIỚI HẠN 5;
Tại sao bạn lại yêu cầu truy vấn con tiếp theo?
Chúng ta có thể không chỉ sử dụng phần WHERE customer_id IN của phần SELECT ngoài cùng ở đây không?
Hãy xem với một phương pháp thực hành.
Tôi sẽ xóa AS top_five khỏi truy vấn con và thử truy vấn ngoài cùng với nó ngay bây giờ:
dvdrental=> SELECT first_name, last_name, email
FROM customer
WHERE customer_id IN
(SELECT DISTINCT customer_id, SUM(amount)
FROM payment
WHERE extract(month from payment_date) = 4
AND extract(day from payment_date) BETWEEN 10 AND 13
GROUP BY customer_id
HAVING SUM(amount) > 30
ORDER BY SUM(amount) DESC
LIMIT 5);
ERROR: subquery has too many columns
LINE 3: WHERE customer_id IN (
Ở đây, tư cách thành viên IN đang được thử nghiệm chỉ với cột customer_id, nhưng Bảng gốc trả về hai cột và PostgreSQL cho chúng tôi biết.
Một cách khắc phục là sử dụng một truy vấn con khác. Chỉ chọn customer_id từ tập hợp kết quả Bảng gốc, sẽ tạo truy vấn con lồng nhau bên trong tiếp theo.
Bây giờ, vị từ IN chứa nhiều hàng giá trị của một cột để kiểm tra tư cách thành viên so với mệnh đề WHERE cho customer_id để đặt kết quả cuối cùng.
Tại sao nó lại quan trọng?
Việc sử dụng truy vấn con theo cách này rất hiệu quả do số lượng giá trị có thể được kiểm tra với vị từ IN ().
Hãy tưởng tượng nếu có 100? Hoặc nhiều hơn nữa?
' Mã hóa cứng 'tất cả chúng trong danh sách IN () có thể trở nên có vấn đề và dễ xảy ra lỗi khi khối lượng giá trị tăng lên.
4. create_series ()
Chức năng quay lại tập hợp này, rất tiện dụng và siêu thú vị khi sử dụng và khám phá. Tôi đã sử dụng create_series () trong các ví dụ trên, nhưng nó xứng đáng được nói chuyện riêng. Tập trung nhiều hơn vào chức năng và khả năng.
Tôi thấy create_series () hữu ích cho các truy vấn so sánh trong đó một số hoặc tất cả dữ liệu bị thiếu.
Hoặc chỉ một phần dữ liệu có sẵn tại thời điểm tôi đang khám phá. Một cách sử dụng hữu ích là điền các bảng với ' dữ liệu giả '.
Để bắt đầu, chúng ta sẽ tạo một bảng đơn giản:
trial=> CREATE TABLE tbl_1(
trial(> tb_id SERIAL PRIMARY KEY,
trial(> some_day DATE,
trial(> an_amt NUMERIC(4,2));
CREATE TABLE
Sau đó, sử dụng create_series () làm GIÁ TRỊ cho câu lệnh INSERT của chúng tôi:
trial=> INSERT INTO tbl_1(some_day, an_amt)
VALUES(
generate_series('2018-04-01','2018-04-15',INTERVAL '1 day'),
generate_series(2.43, 34.20, 1.03));
INSERT 0 31
Sau đó, tạo bảng thứ hai
trial=> CREATE TABLE tbl_2(
tb2_id SERIAL PRIMARY KEY,
some_day2 DATE,
an_amt2 NUMERIC(4,2));
CREATE TABLE
Ngoài ra, hãy điền nó bằng cách sử dụng create_series () trong câu lệnh INSERT:
trial=> INSERT INTO tbl_2(some_day2, an_amt2)
VALUES(
generate_series('2018-05-16','2018-05-31',INTERVAL '1 day'),
generate_series(15.43, 31., 1.03));
INSERT 0 16
Tại sao nó lại quan trọng?
Để nhắc lại, create_series () rất hữu ích để tạo dữ liệu giả hoặc dữ liệu thực hành.
Tôi nhận thấy việc bắt chước phạm vi tháng hoặc ngày để so sánh là điều đặc biệt với create_series (). Tham khảo phần 1 và CTE ở đó, minh chứng cho việc sử dụng này.
Tạo một tập hợp dữ liệu hoàn chỉnh với create_series () và sử dụng để so sánh với dữ liệu được lưu trữ để xác định xem có dữ liệu nào bị thiếu cũng có giá trị lớn hay không.
5. Truy vấn có hàm tổng hợp COUNT ().
Hàm tổng hợp đơn giản nhưng hiệu quả này nên có trong kho vũ khí của bất kỳ ai. Đặc biệt là khi khám phá bảng hoặc tập dữ liệu lần đầu tiên.
Ý tôi là, bạn có thực sự muốn ' CHỌN mọi thứ 'từ một bảng có 1 triệu hàng?
Xác định với COUNT (*) có bao nhiêu bản ghi trước khi bạn tải lên.
Hãy cùng tìm hiểu xem bàn phim có bao nhiêu hàng trong bảng cho thuê DVD giả này:
dvdrental=> SELECT COUNT(*)
dvdrental-> FROM film;
count
-------
1000
(1 row)
Mặc dù không hoàn toàn rộng như hơn 1 triệu hàng, nhưng tôi chắc chắn rằng bạn sẽ thấy sự hữu ích.
Để trả về số lượng hàng cụ thể, COUNT (*) có thể được lọc bằng mệnh đề WHERE.
Hãy xem có bao nhiêu bộ phim có xếp hạng 'G':
dvdrental=> SELECT COUNT(*)
dvdrental-> FROM film
dvdrental-> WHERE rating = 'G';
count
-------
178
(1 row)
Có một dạng COUNT () khác cần lưu ý. COUNT (some_expression) .
Sự khác biệt giữa chúng là:
- COUNT (*) trả về tổng tất cả các hàng đầu vào (bao gồm NULLS và các hàng trùng lặp).
- COUNT ( some_expression ) đếm số hàng đầu vào không phải NULL.
Khi được sử dụng cùng với từ khóa DISTINCT, COUNT () sẽ loại bỏ các mục nhập trùng lặp và chỉ trả lại các giá trị duy nhất.
Hãy xem điều đó đang hoạt động bằng cách sử dụng COUNT () với DISTINCT để xác định có bao nhiêu loại xếp hạng duy nhất hiện nay:
dvdrental=> SELECT COUNT(DISTINCT rating) FROM film;
count
-------
5
(1 row)
Với truy vấn này, chúng tôi biết có 5 loại xếp hạng.
Tại sao nó lại quan trọng?
Tùy thuộc vào những gì đang được theo dõi hoặc được nhắm mục tiêu, việc biết có bao nhiêu thứ tồn tại có thể rất quan trọng. Do đó, việc sử dụng COUNT (*) hoặc COUNT ( some_expression ) hỗ trợ với những loại thách thức này.
Chỉ cần nhớ COUNT (*) không bỏ qua NULL. Tất cả các hàng, các giá trị trùng lặp và NULL được bao gồm, được trả về như một phần của số cuối cùng.
6. CẬP NHẬT nhiều hàng bằng biểu thức CASE.
Giả sử chúng ta có bảng này:
trial=> SELECT * FROM reward_members;
rm_id | expense_amt | member_status
-------+-------------+---------------
1 | 1245.33 | gold
2 | 1300.49 | gold
3 | 900.20 | bronze
4 | 2534.44 | platinum
5 | 600.19 | bronze
6 | 1001.55 | silver
7 | 1097.99 | silver
8 | 3033.33 | platinum
(8 rows)
Chúng tôi cần đổi tên cột member_status và thêm ' nhóm 'đến cuối tên hiện tại cho mỗi bản ghi.
Đối với người mới bắt đầu, nhiều câu lệnh CẬP NHẬT riêng lẻ sẽ không có vấn đề gì.
Tuy nhiên, một biểu thức CASE đơn lẻ cũng có thể.
trial=> UPDATE reward_members
SET member_status = (
CASE member_status
WHEN 'gold' THEN 'gold_group'
WHEN 'bronze' THEN 'bronze_group'
WHEN 'platinum' THEN 'platinum_group'
WHEN 'silver' THEN 'silver_group'
END
)
WHERE member_status IN ('gold', 'bronze','platinum', 'silver');
UPDATE 8
Hãy truy vấn lại bảng để xem các thay đổi:
trial=> SELECT * FROM reward_members;
rm_id | expense_amt | member_status
-------+-------------+----------------
1 | 1245.33 | gold_group
2 | 1300.49 | gold_group
3 | 900.20 | bronze_group
4 | 2534.44 | platinum_group
5 | 600.19 | bronze_group
6 | 1001.55 | silver_group
7 | 1097.99 | silver_group
8 | 3033.33 | platinum_group
(8 rows)
Tất cả cập nhật đều thành công.
Tại sao nó lại quan trọng?
Bạn có thể tưởng tượng điều này sẽ mất bao nhiêu vòng đến máy chủ nếu nhiều câu lệnh UPDATE riêng lẻ đã được chạy. Trong thực tế, chỉ có 4 cho ví dụ này. Tuy nhiên, tiềm năng cho nhiều người vẫn luôn ở đó.
Tuy nhiên, bằng cách sử dụng CẬP NHẬT với biểu thức CASE, chúng tôi chỉ gửi một truy vấn thay thế.
7. SAO CHÉP và \ sao chép
PostgreSQL cung cấp COPY, một lệnh để xuất dữ liệu giữa các tệp và bảng.
Hãy chắc chắn và truy cập liên kết được cung cấp để xem số lượng phong phú các tùy chọn có sẵn với COPY.
Một lưu ý quan trọng liên quan đến SAO CHÉP. Cần có đặc quyền vai trò SUPERUSER để thực thi lệnh này.
Siêu lệnh psql \ copy là một giải pháp thay thế cho những người dùng không được coi là thuộc tính vai trò này. Chúng ta sẽ lần lượt truy cập lệnh đó trong thời gian ngắn.
Đầu tiên, hãy chạy lệnh COPY để xuất các cột nhất định sang tệp CSV trên máy cục bộ.
Giả sử chúng ta có kết quả truy vấn này để xuất:
trial=# SELECT expense_amt, member_status
trial-# FROM reward_members
trial-# WHERE member_status = 'gold_group';
expense_amt | member_status
-------------+---------------
1245.33 | gold_group
1300.49 | gold_group
(2 rows)
Với COPY, chúng tôi có thể sử dụng câu lệnh SELECT đó để hoàn tất quá trình xuất này.
trial=# COPY (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'gold_group')
TO '/home/linux_user_here/awards_to_honor.csv'
DELIMITER ','
CSV HEADER;
COPY 2
* Lưu ý:Theo tài liệu, truy vấn phải nằm trong dấu ngoặc đơn.
Bây giờ chúng ta hãy kiểm tra nội dung của tệp đó:
$ cat awards_to_honor.csv
expense_amt,member_status
1245.33,gold_group
1300.49,gold_group
Chúng ta có thể thấy dòng đầu tiên chứa HEADER (là các tên cột) và cả hai dòng đều có dữ liệu cost_amt và member_status cho cả hai cột được trả về từ bộ lọc mệnh đề WHERE.
Một lưu ý quan trọng khác mà tôi đã phát hiện ra khi thực hiện lệnh COPY ở trên.
Người dùng phải có đặc quyền để ghi vào tệp ở cấp hệ điều hành.
Trong trường hợp của tôi, đã khắc phục bằng:
$ sudo chown postgres awards_to_honor.csv
Thay vào đó, bạn có thể tránh sự cố này bằng cách ghi vào tệp hệ thống mà người dùng hiện tại có quyền truy cập, chẳng hạn như / tmp (được hiển thị bên dưới.)
trial=# COPY (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'gold_group')
TO '/tmp/awards_to_honor.csv'
DELIMITER ','
CSV HEADER;
COPY 2
Tuy nhiên, một trong những vai trò thử nghiệm của tôi không có thuộc tính SUPERUSER, đã gặp sự cố khi ghi vào tệp / tmp.
Xem bên dưới để xác nhận:
trial=# SET role log_user; -- changing from postgres user to log_user
SET
Bây giờ đang cố gắng thực hiện cùng một lệnh COPY, ghi vào thư mục / tmp
trial=> COPY (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'gold_group')
TO '/tmp/awards_to_honor2.csv'
DELIMITER ','
CSV HEADER;
ERROR: must be superuser to COPY to or from a file
HINT: Anyone can COPY to stdout or from stdin. psql's \copy command also works for anyone.
Có lẽ một biện pháp tốt hơn, như được đề xuất trong HINT :, đối với các vai trò không có thuộc tính SUPERUSER, là lệnh meta psql \ copy.
Thay vào đó, hãy thực hiện một loại lệnh tương tự với \ copy bằng cách sử dụng cùng một vai trò mà không cần thuộc tính SUPERUSER đó.
trial=> \copy (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'silver_group')
TO '/home/linux_user_here/more_awards.csv'
DELIMITER ','
CSV HEADER;
COPY 2
Không có vấn đề gì ở đó.
Và nội dung của tệp,
$ cat more_awards.csv
expense_amt,member_status
1001.55,silver_group
1097.99,silver_group
Cũng hoạt động cho thư mục / tmp:
trial=> \copy (SELECT expense_amt, member_status
FROM reward_members
WHERE member_status = 'silver_group')
TO '/tmp/more_awards.csv'
DELIMITER ','
CSV HEADER;
COPY 2
Nội dung tương tự cũng có trong tệp đã viết:
trial=> \! cat /tmp/more_awards.csv
expense_amt,member_status
1001.55,silver_group
1097.99,silver_group
Tại sao nó lại quan trọng?
Nhập dữ liệu vào PostgreSQL qua tệp là một phương pháp tải lên hàng loạt chắc chắn. Mặc dù tất cả đều không được đề cập trong bài đăng blog này, cả hai COPY và \ copy đều cung cấp một số tùy chọn để làm việc với các định dạng tệp và phần mở rộng khác nhau.
Trên cùng một mã thông báo, việc xuất dữ liệu từ các bảng hoặc các cột cụ thể cũng dễ dàng được xử lý bằng cả hai lệnh này.
8. psql \ help meta-command
Bạn đang ở trong một phiên dòng lệnh psql. Bạn muốn biết về cú pháp lệnh CREATE INDEX?
Không cần và truy cập trình duyệt hoặc tài liệu khác.
Hãy thử cái này thay thế:
trial=> \help CREATE INDEX
Command: CREATE INDEX
Description: define a new index
Syntax:
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON table_name [ USING method ]
( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
[ WITH ( storage_parameter = value [, ... ] ) ]
[ TABLESPACE tablespace_name ]
[ WHERE predicate ]
Để biết có văn bản trợ giúp nào, bạn có thể tự chạy \ help và nhận danh sách các tùy chọn có sẵn.
Tôi sẽ không liệt kê tất cả chúng ở đây, chỉ cần biết rằng tùy chọn có sẵn.
Tại sao nó lại quan trọng?
Thực tế là lệnh meta này siêu dễ sử dụng, mạnh mẽ và tiện lợi là những ưu điểm đủ để đề cập đến nó ở đây. Nó đã giúp tôi tiết kiệm rất nhiều thời gian để tìm kiếm trong các tài liệu khác. Và tất nhiên, là một người mới, tôi sử dụng nó khá thường xuyên!
Kết luận
Đây không phải là một danh sách đầy đủ. Cũng không phải là ' hãy kết thúc tất cả 'của các truy vấn và thao tác dữ liệu.
Chỉ có tôi mới tiếp nhận những thứ khơi gợi sự quan tâm của tôi và nói chuyện với tôi khi tôi tiếp tục học hỏi và phát triển với vai trò Nhà phát triển SQL. Tôi hy vọng thông qua bài đăng trên blog này, bạn sẽ tìm thấy các trường hợp sử dụng cho các truy vấn và lệnh ở trên, triển khai những trường hợp bạn thấy phù hợp.