Làm cách nào để tạo hàm tổng hợp do người dùng xác định?


8

Tôi cần một hàm tổng hợp mà MySQL không cung cấp.

Tôi muốn nó có hương vị SQL của MySQL (nghĩa là không phải bằng C).

Làm thế nào để tôi làm điều này? Những gì tôi bị mắc kẹt là tạo ra một hàm tổng hợp - các tài liệu dường như không đề cập đến cách thực hiện.

Ví dụ về việc sử dụng productchức năng mong muốn :

mysql> select product(col) as a from `table`;
+------+
| a    |
+------+
|  144 |
+------+
1 row in set (0.00 sec)

mysql> select col, product(col) as a from `table` group by col;
+-----+------+
| col | a    |
+-----+------+
|   6 |   36 |
|   4 |    4 |
+-----+------+
2 rows in set (0.01 sec)

Câu trả lời:


7

Theo tài liệu http://dev.mysql.com/doc/refman/5.5/en/adding-udf.html chỉ có thể viết các hàm tổng hợp trong C. Xin lỗi!


Hoặc là C hoặc C ++. Không phải SQL, dù sao đi nữa.
Mike Sherrill 'Nhớ lại mèo'

1
Tôi đoán bất kỳ ngôn ngữ nào có thể tạo thư viện nhị phân ở định dạng nhị phân được nền tảng hỗ trợ với các quy ước gọi C.
Colin 't Hart

Tôi không biết. Nó được ghi lại là "C hoặc C ++ (hoặc ngôn ngữ khác có thể sử dụng các quy ước gọi C)" trong phiên bản 5.0. Các tài liệu đã bỏ "hoặc một ngôn ngữ khác có thể sử dụng các quy ước gọi C" trong phiên bản 5.1. Đó là một cụm từ lạ để bỏ.
Mike Sherrill 'Nhớ lại mèo'

nó có sẵn trong các phiên bản mysql gần đây không (sau vài năm)?
Dinesh

9

Tôi không biết có cách nào để xác định hàm tổng hợp mới không, không phải là không làm phiền với mã nguồn MySQL.

Nhưng nếu số của bạn đều dương, bạn cũng có thể xuất phát từ danh tính số học:

log( product( Ai ) ) = sum( log( Ai ) )

mà bạn có thể sử dụng EXP(SUM(LOG(x)))để tính toán PRODUCT(x). Kiểm tra trong SQL-Fiddle :

SELECT EXP(SUM(LOG(a))) AS product
FROM t ;

SELECT col, EXP(SUM(LOG(a))) AS product
FROM t 
GROUP BY col ;

Khi dữ liệu có thể có 0, nó phức tạp hơn một chút:

SELECT (NOT EXISTS (SELECT 1 FROM t WHERE a = 0)) 
       * EXP(SUM(LOG(a))) AS p
FROM t 
WHERE a > 0 ;

SELECT d.col, 
       (NOT EXISTS (SELECT 1 FROM t AS ti WHERE ti.col = d.col AND ti.a = 0)) 
       * COALESCE(EXP(SUM(LOG(t.a))),1)  AS p
FROM 
    ( SELECT DISTINCT col
      FROM t
    ) AS d
  LEFT JOIN
    t  ON  t.col = d.col
       AND t.a > 0
GROUP BY d.col ;

Đã thử nghiệm tại SQL-Fiddle


Đối với các DBMS khác, không có tự động chuyển đổi các giá trị boolean của MySQL sang số nguyên,

(NOT EXISTS (SELECT ...))

nên được thay thế bằng:

(CASE WHEN EXISTS (SELECT 1...) THEN 0 ELSE 1 END) 

Cụ thể đối với Oracle, sẽ cần thêm một vài thay đổi, mà không thay đổi logic của câu trả lời, chỉ vì Oracle không tuân theo tiêu chuẩn ANSI nghiêm ngặt trong một số lĩnh vực. Đã thử nghiệm tại SQL-Fiddle-2


2
Thật ngọt ngào. Toán trung học đã trở lại ám ảnh tôi. +1 !!!
RolandoMySQLDBA

1
Toán học thú vị, nhưng tôi thực sự muốn biết làm thế nào để tạo một hàm tổng hợp nói chung. productchỉ được coi là một ví dụ của một số.
Matt Fenwick

Điều này khá thú vị, nhưng không hoạt động nếu bất kỳ giá trị nào bằng 0, vì log (0) không được xác định.
jameshfisher

@jameshfisher Đúng. Người ta có thể dễ dàng viết điều kiện bổ sung, kiểm tra các số không (tất nhiên sản phẩm sẽ bằng 0). Tôi đã không nghĩ rằng tại thời điểm đó là cần thiết để thêm sự phức tạp đó.
ypercubeᵀᴹ

Tôi không rõ cách tốt nhất để thêm điều kiện đó. Chúng ta không thể thêm điều kiện vào hàm bên trong của các giá trị: vì chúng ta muốn điều đó PRODUCT(..., 0, ...) = 0, chúng ta muốn điều đó EXP(SUM(..., f(0), ...)) = 0, đối với một số fthứ chúng ta chọn, nhưng để thỏa mãn điều này, chúng ta cần điều đó SUM(..., f(0), ...) = LOG(0)- một lần nữa bị cản trở bởi cùng một vấn đề đó (0 ) không định nghĩa được. Chúng ta cần kiểm tra sự hiện diện của số 0 theo một cách khác, ví dụ MIN(ABS(a)) = 0. Vì vậy, chúng tôi sẽ có SELECT CASE WHEN MIN(ABS(a)) = 0 THEN 0 ELSE EXP(SUM(LOG(a))) END AS product. Đây có phải là điều bạn đang nghĩ đến?
jameshfisher

3

Để tìm hiểu cách câu cá, tôi đã biên soạn và cài đặt thành công "Xin chào, Thế giới!" UDF (chức năng do người dùng định nghĩa) cho MySQL được tìm thấy ở đây . Tệp hello_world.so (sau khi được tuân thủ gcc -shared -o hello_world.so -I /usr/include/mysql hello_world.c) phải được lưu trữ trong / usr / lib / mysql / plugins / với 755 quyền trên các hệ thống linux của Ubuntu. ["-I / usr / include / mysql" là đường dẫn đến các tệp tiêu đề mysql; Tôi thấy mã của mình sẽ không biên dịch nếu không có tham số này, nhưng YMMV.]

Chương trình không làm gì ngoài việc in ra chuỗi "Xin chào, Thế giới!" cho mỗi bản ghi trong tập dữ liệu kết quả của một truy vấn, nhưng đó là tất cả những gì nó phải làm. Tôi sẽ cố gắng viết một hàm tổng hợp NHỎ trong vài ngày tới. Có một ví dụ về hàm tổng hợp tính toán chi phí trung bình của một nhóm các bản ghi giá và số lượng; cuối cùng thì hàm SMALL không khác với hàm đó.

Hi vọng điêu nay co ich.

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.