Làm thế nào để tôi có hiệu quả nhận được các hàng tương ứng gần đây nhất?


53

Tôi có một mẫu truy vấn phải rất phổ biến, nhưng tôi không biết cách viết một truy vấn hiệu quả cho nó. Tôi muốn tìm kiếm các hàng của một bảng tương ứng với "ngày gần đây nhất không phải sau" các hàng của bảng khác.

Tôi có một bảng, inventoryđại diện cho hàng tồn kho tôi giữ vào một ngày nào đó.

date       | good | quantity
------------------------------
2013-08-09 | egg  | 5
2013-08-09 | pear | 7
2013-08-02 | egg  | 1
2013-08-02 | pear | 2

và một bảng, "giá" nói, giữ giá hàng hóa vào một ngày nhất định

date       | good | price
--------------------------
2013-08-07 | egg  | 120
2013-08-06 | pear | 200
2013-08-01 | egg  | 110
2013-07-30 | pear | 220

Làm cách nào tôi có thể có được giá "gần đây nhất" cho mỗi hàng của bảng kiểm kê một cách hiệu quả

date       | pricing date | good | quantity | price
----------------------------------------------------
2013-08-09 | 2013-08-07   | egg  | 5        | 120
2013-08-09 | 2013-08-06   | pear | 7        | 200
2013-08-02 | 2013-08-01   | egg  | 1        | 110
2013-08-02 | 2013-07-30   | pear | 2        | 220

Tôi biết một cách để làm điều này:

select inventory.date, max(price.date) as pricing_date, good
from inventory, price
where inventory.date >= price.date
and inventory.good = price.good
group by inventory.date, good

và sau đó tham gia truy vấn này một lần nữa để kiểm kê. Đối với các bảng lớn, ngay cả khi thực hiện truy vấn đầu tiên (không tham gia lại vào kho) rất chậm. Tuy nhiên, vấn đề tương tự được giải quyết nhanh chóng nếu tôi chỉ đơn giản sử dụng ngôn ngữ lập trình của mình để đưa ra một max(price.date) ... where price.date <= date_of_interest ... order by price.date desc limit 1truy vấn cho mỗi truy vấn date_of_interesttừ bảng kiểm kê, vì vậy tôi biết không có trở ngại tính toán nào. Tuy nhiên, tôi muốn giải quyết toàn bộ vấn đề bằng một truy vấn SQL duy nhất, vì nó sẽ cho phép tôi thực hiện xử lý SQL tiếp theo trên kết quả của truy vấn.

Có một cách tiêu chuẩn để làm điều này một cách hiệu quả? Cảm giác như nó phải xuất hiện thường xuyên và cần có một cách để viết một truy vấn nhanh cho nó.

Tôi đang sử dụng Postgres, nhưng câu trả lời chung chung về SQL sẽ được đánh giá cao.


3
Được bình chọn để được chuyển sang DBA.SE vì đây là một câu hỏi hiệu quả. Chúng tôi có thể viết truy vấn theo một số cách khác nhau nhưng điều đó sẽ không làm cho nó nhanh hơn nhiều.
ypercubeᵀᴹ

5
Bạn có thực sự cần tất cả hàng hóa cho tất cả các ngày từ một truy vấn không? Có vẻ như một yêu cầu không thể? Thông thường hơn người ta sẽ lấy giá cho một ngày cụ thể hoặc (các) giá cho một hàng hóa cụ thể (tại một ngày cụ thể). Những truy vấn thay thế có thể dễ dàng hưởng lợi nhiều hơn từ các chỉ số (thích hợp). Chúng ta cũng cần biết: các số chính (có bao nhiêu hàng trong mỗi bảng?), Định nghĩa bảng hoàn chỉnh bao gồm. kiểu dữ liệu, các ràng buộc, chỉ mục, ... (sử dụng \d tbltrong psql), phiên bản Postgres và min của bạn. / tối đa số lượng mỗi giá tốt.
Erwin Brandstetter

@ErwinBrandstetter Bạn đang yêu cầu tôi chấp nhận câu trả lời? Tôi không thực sự đủ điều kiện để biết cái nào là tốt nhất, mặc dù vì bạn có nhiều người ủng hộ nhất nên tôi rất vui khi chấp nhận nó.
Tom Ellis

Chỉ chấp nhận nếu nó trả lời câu hỏi của bạn hoặc làm việc cho bạn. Bạn thậm chí có thể để lại một bình luận về cách bạn tiến hành nếu điều đó có thể giúp các trường hợp liên quan. Nếu bạn cảm thấy câu hỏi của bạn chưa được trả lời, hãy cho chúng tôi biết.
Erwin Brandstetter

1
Sau đó tôi phải xin lỗi, vì mặc dù tôi đã nhận được câu trả lời có vẻ là câu trả lời xuất sắc nhưng tôi không còn làm việc với vấn đề gây ra câu hỏi nữa nên tôi không thể đánh giá đâu là câu trả lời hay nhất, hoặc thực sự là ai trong số họ thực sự phù hợp với trường hợp sử dụng của tôi (như nó đã từng). Nếu có một số ettiquette DBA.Stackexchange tôi nên theo dõi trong trường hợp này xin vui lòng cho tôi biết.
Tom Ellis

Câu trả lời:


42

rất nhiều phụ thuộc vào hoàn cảnh và yêu cầu chính xác. Hãy xem xét nhận xét của tôi cho câu hỏi .

Giải pháp đơn giản

Với DISTINCT ONtrong Postgres:

SELECT DISTINCT ON (i.good, i.the_date)
       i.the_date, p.the_date AS pricing_date, i.good, p.price
FROM   inventory  i
LEFT   JOIN price p ON i.good = p.good AND i.the_date >= p.the_date
ORDER  BY i.good, i.the_date, p.the_date DESC;

Kết quả đặt hàng.

Hoặc với NOT EXISTSSQL tiêu chuẩn (hoạt động với mọi RDBMS mà tôi biết):

SELECT i.the_date, p.the_date AS pricing_date, i.good, i.quantity, p.price
FROM   inventory  i
LEFT   JOIN price p ON p.good = i.good AND p.the_date <= i.the_date
WHERE  NOT EXISTS (
   SELECT 1 FROM price p1
   WHERE  p1.good = p.good
   AND p1.the_date <= i.the_date
   AND p1.the_date >  p.the_date
   );

Kết quả tương tự, nhưng với thứ tự sắp xếp tùy ý - trừ khi bạn thêm ORDER BY.
Tùy thuộc vào phân phối dữ liệu, yêu cầu chính xác và chỉ số, một trong những điều này có thể nhanh hơn.
Nói chung, DISTINCT ONlà người chiến thắng và bạn nhận được một kết quả được sắp xếp trên đầu trang của nó. Nhưng đối với một số trường hợp, các kỹ thuật truy vấn khác nhanh hơn (nhiều). Xem bên dưới.

Các giải pháp với các truy vấn con để tính giá trị tối đa / tối thiểu thường chậm hơn. Các biến thể với CTE thường chậm hơn.

Chế độ xem đơn giản (như được đề xuất bởi một câu trả lời khác) không giúp ích gì cho hiệu suất trong Postgres.

Câu đố SQL.


Giải pháp đúng

Chuỗi và đối chiếu

Trước hết, bạn phải chịu một bố trí bảng phụ tối ưu. Nó có vẻ tầm thường, nhưng bình thường hóa lược đồ của bạn có thể đi một chặng đường dài.

Sắp xếp theo loại ký tự ( text,, varchar...) phải được thực hiện theo ngôn ngữ địa phương - cụ thể là THU THẬP . Nhiều khả năng DB của bạn sử dụng một số bộ quy tắc cục bộ (như, trong trường hợp của tôi de_AT.UTF-8:). Tìm hiểu với:

SHOW lc_collate;

Điều này làm cho việc sắp xếp và tìm kiếm chỉ mục chậm hơn . Chuỗi của bạn càng dài (tên hàng hóa) càng tệ. Nếu bạn không thực sự quan tâm đến các quy tắc đối chiếu trong đầu ra của mình (hoặc thứ tự sắp xếp nào cả), điều này có thể nhanh hơn nếu bạn thêm COLLATE "C":

SELECT DISTINCT ON (i.good COLLATE "C", i.the_date)
       i.the_date, p.the_date AS pricing_date, i.good, p.price
FROM   inventory  i
LEFT   JOIN price p ON i.good = p.good AND i.the_date >= p.the_date
ORDER  BY i.good COLLATE "C", i.the_date, p.the_date DESC;

Lưu ý cách tôi thêm đối chiếu ở hai nơi.
Hai lần nhanh nhất trong thử nghiệm của tôi với mỗi hàng 20 nghìn và các tên rất cơ bản ('good123').

Mục lục

Nếu truy vấn của bạn được cho là sử dụng một chỉ mục, các cột có dữ liệu ký tự phải sử dụng đối chiếu phù hợp ( goodtrong ví dụ):

CREATE INDEX inventory_good_date_desc_collate_c_idx
ON price(good COLLATE "C", the_date DESC);

Hãy chắc chắn đọc hai chương cuối của câu trả lời liên quan này trên SO:

Bạn thậm chí có thể có nhiều chỉ mục với các đối chiếu khác nhau trên cùng một cột - nếu bạn cũng cần hàng hóa được sắp xếp theo đối chiếu khác (hoặc mặc định) trong các truy vấn khác.

Bình thường hóa

Các chuỗi dự phòng (tên của hàng hóa) cũng làm mờ các bảng và chỉ mục của bạn, điều này làm cho mọi thứ thậm chí chậm hơn. Với cách bố trí bảng thích hợp, bạn có thể tránh được hầu hết các vấn đề để bắt đầu. Có thể trông như thế này:

CREATE TABLE good (
  good_id serial PRIMARY KEY
, good    text   NOT NULL
);

CREATE TABLE inventory (
  good_id  int  REFERENCES good (good_id)
, the_date date NOT NULL
, quantity int  NOT NULL
, PRIMARY KEY(good_id, the_date)
);

CREATE TABLE price (
  good_id  int     REFERENCES good (good_id)
, the_date date    NOT NULL
, price    numeric NOT NULL
, PRIMARY KEY(good_id, the_date));

Các khóa chính tự động cung cấp (gần như) tất cả các chỉ số chúng ta cần.
Tùy thuộc vào thiếu chi tiết, một chỉ số multicolumn trên pricevới thứ tự giảm dần trên cột thứ hai có thể cải thiện hiệu suất:

CREATE INDEX price_good_date_desc_idx ON price(good, the_date DESC);

Một lần nữa, đối chiếu phải phù hợp với truy vấn của bạn (xem bên trên).

Trong Postgres 9.2 trở lên, "các chỉ số che phủ" cho các lần quét chỉ mục có thể giúp nhiều hơn - đặc biệt là nếu các bảng của bạn giữ các cột bổ sung, làm cho bảng lớn hơn đáng kể so với chỉ mục che phủ.

Các truy vấn kết quả này nhanh hơn nhiều:

KHÔNG TỒN TẠI

SELECT i.the_date, p.the_date AS pricing_date, g.good, i.quantity, p.price
FROM   inventory  i
JOIN   good       g USING (good_id)
LEFT   JOIN price p ON p.good_id = i.good_id AND p.the_date <= i.the_date
AND    NOT EXISTS (
   SELECT 1 FROM price p1
   WHERE  p1.good_id = p.good_id
   AND    p1.the_date <= i.the_date
   AND    p1.the_date >  p.the_date
   );

KHOẢNG CÁCH TRÊN

SELECT DISTINCT ON (i.the_date)
       i.the_date, p.the_date AS pricing_date, g.good, i.quantity, p.price
FROM   inventory  i
JOIN   good       g USING (good_id)
LEFT   JOIN price p ON p.good_id = i.good_id AND p.the_date <= i.the_date
ORDER  BY i.the_date, p.the_date DESC;

Câu đố SQL.


Giải pháp nhanh hơn

Nếu điều đó vẫn chưa đủ nhanh, có thể có giải pháp nhanh hơn.

JOIN LATERALTruy vấn CTE / / tương quan

Đặc biệt đối với phân phối dữ liệu với nhiều mức giá cho mỗi hàng hóa :

Quan điểm cụ thể hóa

Nếu bạn cần chạy cái này thường xuyên và nhanh chóng, tôi khuyên bạn nên tạo một cái nhìn cụ thể hóa. Tôi nghĩ thật an toàn khi giả định rằng giá cả và hàng tồn kho cho những ngày qua hiếm khi thay đổi. Tính kết quả một lần và lưu trữ ảnh chụp nhanh dưới dạng xem cụ thể.

Postgres 9.3+ có hỗ trợ tự động cho các khung nhìn cụ thể hóa. Bạn có thể dễ dàng thực hiện một phiên bản cơ bản trong các phiên bản cũ hơn.


3
Các price_good_date_desc_idxchỉ số bạn khuyên đáng kể cải thiện hiệu suất cho một truy vấn tương tự của tôi. Kế hoạch truy vấn của tôi đã đi từ một chi phí 42374.01..42374.86xuống 0.00..37.12!
cimmanon

@cimmanon: Đẹp quá! Tính năng truy vấn cốt lõi của bạn là gì? KHÔNG TỒN TẠI? KHOẢNG CÁCH TRÊN NÀO? NHÓM THEO?
Erwin Brandstetter

Sử dụng DISTINCT ON
cimmanon

6

FYI, tôi đã sử dụng mssql 2008, vì vậy Postgres sẽ không có chỉ số "bao gồm". Tuy nhiên, sử dụng lập chỉ mục cơ bản được hiển thị bên dưới sẽ thay đổi từ các phép nối băm để hợp nhất các phép nối trong Postgres: http://explain.depesz.com/s/eF6 (không có chỉ mục) http://explain.depesz.com/s/j9x ( với chỉ số về tiêu chí tham gia)

Tôi đề nghị chia truy vấn của bạn thành hai phần. Đầu tiên, một chế độ xem (không nhằm cải thiện hiệu suất) có thể được sử dụng trong nhiều bối cảnh khác thể hiện mối quan hệ của ngày tồn kho và ngày định giá.

create view mostrecent_pricing_dates_per_good as
select i.good,i.date i_date,max(p.date)p_date
  from inventory i
  join price p on i.good = p.good and i.date >= p.date
 group by i.good,i.date;

Sau đó, truy vấn của bạn có thể trở nên đơn giản và dễ dàng hơn để thao tác cho các loại khác nếu yêu cầu (chẳng hạn như sử dụng các liên kết trái để tìm hàng tồn kho mà không có ngày định giá gần đây):

select i.good
       ,i.date inventory_date
       ,i.quantity
       ,p.date pricing_date
       ,p.price       
  from inventory i
  join price p on i.good = p.good
  join mostrecent_pricing_dates_per_good x 
    on i.good = x.good 
   and p.date = x.p_date
   and i.date = x.i_date

Điều này mang lại kế hoạch thực hiện sau: http://sqlfiddle.com/#!3/24f23/1 không lập chỉ mục

... Tất cả các bản quét với một loại đầy đủ. Thông báo chi phí hiệu năng của các trận đấu băm chiếm phần lớn tổng chi phí ... và chúng tôi biết rằng việc quét và sắp xếp bảng là chậm (so với mục tiêu: chỉ số tìm kiếm).

Bây giờ, hãy thêm các chỉ mục cơ bản để giúp các tiêu chí được sử dụng trong liên kết của bạn (Tôi không khẳng định đây là các chỉ mục tối ưu, nhưng chúng minh họa điểm này): http://sqlfiddle.com/#!3/5ec75/1 với lập chỉ mục cơ bản

Điều này cho thấy sự cải thiện. Các hoạt động của vòng lặp lồng nhau (nối bên trong) không còn chiếm bất kỳ tổng chi phí liên quan nào cho truy vấn. Phần còn lại của chi phí hiện được trải đều giữa các lần tìm kiếm chỉ mục (quét tìm hàng tồn kho vì chúng tôi đang kéo từng hàng tồn kho). Nhưng chúng ta vẫn có thể làm tốt hơn vì truy vấn kéo số lượng và giá cả. Để có được dữ liệu đó, sau khi đánh giá critera tham gia, việc tra cứu phải được thực hiện.

Lặp lại cuối cùng sử dụng "bao gồm" trên các chỉ mục để giúp kế hoạch dễ dàng trượt qua và lấy dữ liệu được yêu cầu bổ sung ngay ra khỏi chính chỉ mục. Vì vậy, các tra cứu đã biến mất: http://sqlfiddle.com/#!3/5f143/1 nhập mô tả hình ảnh ở đây

Bây giờ chúng ta có một kế hoạch truy vấn trong đó tổng chi phí của truy vấn được trải đều giữa các hoạt động tìm kiếm chỉ mục rất nhanh. Điều này sẽ gần với mức độ tốt nhất có thể. Chắc chắn các chuyên gia khác có thể cải thiện điều này hơn nữa, nhưng giải pháp xóa đi một vài mối quan tâm lớn:

  1. Nó tạo ra các cấu trúc dữ liệu dễ hiểu trong cơ sở dữ liệu của bạn, dễ dàng soạn thảo và sử dụng lại trong các khu vực khác của ứng dụng.
  2. Tất cả các toán tử truy vấn tốn kém nhất đã được đưa ra khỏi kế hoạch truy vấn bằng cách sử dụng một số chỉ mục cơ bản.

3
Điều này tốt (đối với SQL-Server) nhưng tối ưu hóa cho các DBMS khác nhau trong khi nó có những điểm tương đồng, nó cũng có những khác biệt nghiêm trọng.
ypercubeᵀᴹ

@ypercube đó là sự thật. Tôi đã thêm một số bằng cấp về Postgres. Ý định của tôi là hầu hết quá trình suy nghĩ được minh họa ở đây sẽ áp dụng bất kể các tính năng cụ thể của DBMS.
cocogorilla

Câu trả lời rất sâu sắc, vì vậy tôi sẽ mất một chút thời gian để thử nó. Tôi sẽ cho bạn biết làm thế nào tôi nhận được trên.
Tom Ellis

5

Nếu bạn tình cờ có PostgreSQL 9.3 (phát hành ngày hôm nay) thì bạn có thể sử dụng THAM GIA LATITH.

Tôi không có cách nào để kiểm tra điều này, và chưa bao giờ sử dụng nó trước đây, nhưng từ những gì tôi có thể nói từ tài liệu , cú pháp sẽ giống như:

SELECT  Inventory.Date,
        Inventory.Good,
        Inventory.Quantity,
        Price.Date,
        Price.Price
FROM    Inventory
        LATERAL
        (   SELECT  Date, Price
            FROM    Price
            WHERE   Price.Good = Inventory.Good
            AND     Price.Date <= Inventory.Date
            ORDER BY Price.Date DESC
            LIMIT 1
        ) p;

Điều này về cơ bản tương đương với ỨNG DỤNG của SQL-Server và có một ví dụ hoạt động về điều này trên SQL-Fiddle cho mục đích demo.


5

Như Erwin và những người khác đã lưu ý, một truy vấn hiệu quả phụ thuộc vào rất nhiều biến số và PostgreQuery rất cố gắng để tối ưu hóa việc thực hiện truy vấn dựa trên các biến đó. Nói chung, bạn muốn viết cho rõ ràng trước và sau đó sửa đổi cho hiệu suất sau khi bạn xác định các tắc nghẽn.

Ngoài ra, PostgreSQL có rất nhiều thủ thuật bạn có thể sử dụng để làm cho mọi thứ hiệu quả hơn một chút (chỉ mục một phần cho một) vì vậy tùy thuộc vào tải đọc / ghi của bạn, bạn có thể tối ưu hóa điều này rất xa bằng cách xem xét lập chỉ mục cẩn thận.

Điều đầu tiên để thử là chỉ để xem và tham gia nó:

CREATE VIEW most_recent_rows AS
SELECT good, max(date) as max_date
FROM inventory
GROUP BY good;

Điều này sẽ thực hiện tốt khi làm một cái gì đó như:

SELECT price 
  FROM inventory i
  JOIN goods g ON i.goods = g.description
  JOIN most_recent_rows r ON i.goods = r.goods
 WHERE g.id = 123;

Sau đó, bạn có thể tham gia đó. Truy vấn sẽ kết thúc việc tham gia khung nhìn vào bảng bên dưới, nhưng giả sử bạn có một chỉ mục duy nhất vào (ngày, tốt theo thứ tự đó ), bạn nên đi tiếp (vì đây sẽ là một tra cứu bộ đệm đơn giản). Điều này sẽ hoạt động rất tốt với một vài hàng được tra cứu nhưng sẽ rất kém hiệu quả nếu bạn đang cố gắng tiêu hóa hàng triệu giá hàng hóa.

Điều thứ hai bạn có thể làm là thêm vào bảng kiểm kê một cột bool most_recent và

create unique index on inventory (good) where most_recent;

Sau đó, bạn sẽ muốn sử dụng các kích hoạt để đặt most_recent thành false khi một hàng mới cho hàng hóa được chèn vào. Điều này thêm phức tạp hơn và cơ hội lớn hơn cho các lỗi nhưng nó rất hữu ích.

Một lần nữa rất nhiều điều này phụ thuộc vào các chỉ số thích hợp được đưa ra. Đối với hầu hết các truy vấn ngày gần đây, có lẽ bạn nên có một chỉ mục theo ngày và có thể là một cột nhiều cột bắt đầu bằng ngày và bao gồm cả tiêu chí tham gia của bạn.

Cập nhật bình luận của Per Erwin bên dưới, có vẻ như tôi đã hiểu nhầm điều này. Đọc lại câu hỏi tôi hoàn toàn không chắc chắn những gì đang được hỏi. Tôi muốn đề cập đến trong bản cập nhật vấn đề tiềm năng tôi nhìn thấy là gì và tại sao điều này không rõ ràng.

Thiết kế cơ sở dữ liệu được cung cấp không có IME sử dụng thực sự với hệ thống kế toán và ERP. Nó sẽ hoạt động trong một mô hình định giá hoàn hảo giả thuyết trong đó mọi thứ được bán trong một ngày nhất định của một sản phẩm nhất định có cùng giá. Tuy nhiên, đây không phải là luôn luôn như vậy. Nó thậm chí không phải là trường hợp đối với những thứ như trao đổi tiền tệ (mặc dù một số mô hình giả vờ như vậy). Nếu đây là một ví dụ giả định, nó không rõ ràng. Nếu đó là một ví dụ thực tế, có những vấn đề lớn hơn với thiết kế ở mức dữ liệu. Tôi sẽ giả định ở đây rằng đây là một ví dụ thực tế.

Bạn không thể cho rằng ngày đó chỉ định giá cho một hàng hóa nhất định. Giá trong bất kỳ doanh nghiệp có thể được đàm phán cho mỗi bên đối tác và thậm chí đôi khi trên mỗi giao dịch. Vì lý do này, bạn thực sự nên lưu trữ giá trong bảng thực sự xử lý hàng tồn kho vào hoặc ra (bảng kiểm kê). Trong trường hợp như vậy, bảng ngày / hàng hóa / giá của bạn chỉ xác định giá cơ sở có thể thay đổi dựa trên thương lượng. Trong trường hợp như vậy, vấn đề này chuyển từ một vấn đề báo cáo sang một vấn đề là giao dịch và hoạt động trên một hàng từ mỗi bảng tại một thời điểm. Ví dụ: sau đó bạn có thể tra cứu giá mặc định cho một sản phẩm nhất định vào một ngày nhất định là:

 SELECT price 
   FROM prices p
   JOIN goods g ON p.good = g.good
  WHERE g.id = 123 AND p."date" >= '2013-03-01'
  ORDER BY p."date" ASC LIMIT 1;

Với một chỉ số về giá (tốt, ngày), điều này sẽ hoạt động tốt.

Tôi đây là một ví dụ giả định, có lẽ một cái gì đó gần với những gì bạn đang làm sẽ giúp ích.


Cách most_recenttiếp cận nên hoạt động tốt với giá gần đây nhất hoàn toàn . Dường như OP cần mức giá gần đây nhất so với mỗi ngày tồn kho.
Erwin Brandstetter

Điểm tốt. Đọc lại mặc dù tôi phát hiện ra một số thiếu sót thực tế với dữ liệu được đề xuất nhưng tôi không thể biết đó có phải là một ví dụ giả định không. Như một ví dụ giả định, tôi không thể nói những gì còn thiếu. Có lẽ một bản cập nhật để chỉ ra điều này cũng sẽ theo thứ tự.
Chris Travers

@ChrisTravers: Đây là một ví dụ giả định, nhưng tôi không được tự do đăng sơ đồ thực tế mà tôi đang làm việc. Có lẽ bạn có thể nói một chút về những thiếu sót thực tế mà bạn đã phát hiện ra.
Tom Ellis

Tôi không nghĩ rằng nó cần phải chính xác, nhưng lo lắng về vấn đề bị mất trong câu chuyện ngụ ngôn. Một cái gì đó gần hơn một chút sẽ hữu ích. Vấn đề là với giá cả, giá tại một ngày nhất định có thể là mặc định và do đó bạn sẽ không sử dụng nó để chỉ báo cáo làm mặc định cho mục nhập giao dịch, vì vậy các truy vấn thú vị của bạn thường chỉ có một vài hàng tại thời gian.
Chris Travers

3

Một cách khác là sử dụng chức năng cửa sổ lead()để lấy phạm vi ngày cho mỗi hàng trong giá bảng và sau đó sử dụng betweenkhi tham gia khoảng không quảng cáo. Tôi thực sự đã sử dụng điều này trong cuộc sống thực, nhưng chủ yếu là vì đây là ý tưởng đầu tiên của tôi về cách giải quyết vấn đề này.

with cte as (
  select
    good,
    price,
    date,
    coalesce(lead(date) over(partition by good order by date) - 1
            ,Now()::date) as ndate
  from
    price
)

select * from inventory i join cte on
  (i.good = cte.good and i.date between cte.date and cte.ndate)

SqlFiddle


1

Sử dụng liên kết từ khoảng không quảng cáo để định giá với các điều kiện tham gia giới hạn số lần truy cập từ bảng trợ giúp giá chỉ đến những ngày ở hoặc trước ngày kiểm kê, sau đó trích xuất ngày tối đa và trong đó ngày là ngày cao nhất từ ​​tập hợp con đó

Vì vậy, đối với giá hàng tồn kho của bạn:

 Select i.date, p.Date pricingDate,
    i.good, quantity, price        
 from inventory I join price p 
    on p.good = i.good
        And p.Date = 
           (Select Max(Date from price
            where good = i.good
               and date <= i.Date)

Nếu giá cho bất kỳ hàng hóa được chỉ định nào thay đổi nhiều lần trong cùng một ngày và bạn thực sự chỉ có ngày và không có thời gian trong các cột này, bạn có thể cần áp dụng nhiều hạn chế hơn đối với các liên kết để chỉ chọn một trong các bản ghi thay đổi giá.


Thật không may, dường như không tăng tốc mọi thứ.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.