2015-06-10 16 views
12

trạng:

Tôi muốn tạo một hàm mysql tên XMLify, mà mất trong một chuỗi và một biểu thức mà sẽ trả về một tậpMYSQL UDF hàm trả về XML

XMLify(string, expr)

Chức năng nên quấn từng trường được trả về của mỗi hàng được trả về trong tập hợp, vào thẻ XML của riêng nó. Tên của thẻ phải là tên trường.

ví dụ nhỏ:

select XMLify('foo', (SELECT 1 as `a`, 2 as `b` UNION SELECT 3 as `a`, 4 as `b`)); 

nên quay lại:

<foo><a>1</a><b>2</b></foo><foo><a>3</a><b>4</b></foo> 

Tôi muốn có điều này, bởi vì nó sẽ cho phép tôi để chạy một truy vấn phức tạp với nhiều tham gia và/hoặc truy vấn con phụ thuộc, mà không phải trả lại dữ liệu dư thừa cho máy khách.

Tôi đã có công việc mà không có chức năng tôi muốn xây dựng. Nhưng điều này liên quan đến việc viết các truy vấn khó mà không dễ bảo trì. Xem các ví dụ của tôi bên dưới.

Đảm bảo rằng tên trường là tên nút XML hợp pháp là vì lo lắng sau này. Một khi hàm đứng, tôi sẽ nghĩ về một số thuật toán sẽ lấy tên trường và biến nó thành một số tên nút XML hợp pháp.

Ngoài ra, thoát khỏi dữ liệu XML cũng là điều đáng lo ngại. Việc này sẽ được thực hiện với một chức năng khác có tên là CDATAify, chỉ đơn giản là sẽ bao gồm tất cả dữ liệu vào <![CDATA[]]> và sẽ thoát khỏi bất kỳ sự xuất hiện trước nào của số ]]> trong dữ liệu thành ]]]]><![CDATA[>.

Tôi chưa thể thực hiện việc này bằng cách sử dụng các hàm được lưu trữ trong MySQL, vì chúng không có trong tập hợp kết quả. Ngoài ra, ngay cả khi bạn đã chuyển qua SQL dưới dạng một chuỗi, và sau đó chuẩn bị câu lệnh và thực hiện nó, bạn không thể truy cập các trường nếu bạn chưa biết tên trường.

Vì vậy, bây giờ tôi tự hỏi nếu các thủ thuật có thể được thực hiện với các hàm do người dùng định nghĩa (UDF). Đây là một cái gì đó tôi chưa làm việc với, và tôi muốn tư vấn của bạn ở đây trước khi enbarqueing.

CÂU HỎI:

Vì vậy, câu hỏi của tôi bây giờ là:

  • Để tóm tắt lại, tôi muốn có một hàm MySQL mà tôi có thể vượt qua một biểu thức hoặc tập hợp kết quả, và ở đâu tôi cũng có thể sử dụng tên trường của tập kết quả.
  • Tôi giả định chính xác rằng điều này sẽ không thể thực hiện được trong các chức năng được lưu trữ?
  • UDF có tham gia các phiên làm việc/kết quả của họ được đặt làm đối số không?
  • UDF có cho phép tôi truy cập vào tên trường của tập kết quả, vì vậy tôi có thể sử dụng chúng làm tên thẻ XML
  • Nó cũng hoạt động trên Windows không? Tôi đọc rằng UDF có một số giới hạn
  • Có cách nào tốt hơn mà tôi chưa từng nghĩ đến không?
  • Tôi có thể có một UDF .dll mà tôi có thể tạo trên máy tính phát triển của riêng mình và sau đó sao chép tệp .dll vào máy chủ của tôi và sử dụng nó ở đó không?
  • Làm cách nào để hiển thị chương trình này trên một cuộn? Xin hãy cẩn thận và đưa vào tài khoản mà tôi có MySQL 5.5 64-bit trên một máy tính Windows.

VÍ DỤ:

Hãy tưởng tượng có 3 bảng sau đây:

users:   grades:    toys: 
+----+------+ +--------+-------+ +--------+--------------+ 
| id | name | | userid | grade | | userid | toy   | 
+----+------+ +--------+-------+ +--------+--------------+ 
| 1 | Bart | |  1 |  E | |  1 | slingshot | 
| 2 | Lisa | |  1 |  E | |  1 | Krusty  | 
| .. | ... | |  2 |  A | |  2 | Malibu Stacy | 
| .. | ... | |  2 |  B | |  2 | calculator | 
+----+------+ +--------+-------+ +--------+--------------+ 

kết quả tôi mong muốn sẽ là, giới hạn Bart và Lisa:

<users> 
    <user> 
     <id><![CDATA[1]]></id> 
     <name><![CDATA[Bart]]></name> 
     <grades> 
      <grade><![CDATA[E]]></grade> 
      <grade><![CDATA[E]]></grade> 
     </grades> 
     <toys> 
      <toy><![CDATA[slingshot]]></toy> 
      <toy><![CDATA[Krusty]]></toy> 
     </toys> 
    </user> 
    <user> 
     <id><![CDATA[1]]></id> 
     <name><![CDATA[Lisa]]></name> 
     <grades> 
      <grade><![CDATA[A]]></grade> 
      <grade><![CDATA[B]]></grade> 
     </grades> 
     <toys> 
      <toy><![CDATA[Malibu Stacey]]></toy> 
      <toy><![CDATA[calculator]]></toy> 
     </toys> 
    </user> 
</users> 

xét:

  • Tôi không muốn trong PHP hoặc C# phải truy vấn đầu tiên bảng người dùng và sau đó mỗi người dùng chạy hai truy vấn bổ sung cho điểm và đồ chơi. Bởi vì đối với 1000 người dùng, tôi sẽ chạy các truy vấn 2001.
  • Tôi cũng không muốn chạy truy vấn với tất cả các kết nối và trải qua tập hợp kết quả bằng PHP hoặc C#, vì tên người dùng sẽ được gửi nhiều lần vì số lần đánh số lần đồ chơi. Hãy tưởng tượng có một lĩnh vực người dùng có chứa một đốm màu khổng lồ!
  • Tôi không thể chỉ đơn giản sử dụng GROUP_CONCAT trên các bảng đã tham gia vì các lớp/đồ chơi sẽ vẫn xuất hiện gấp đôi.
  • Và nếu tôi sử dụng GROUP_CONCAT với DISTINCT, tôi sẽ mất các điểm giống nhau, chẳng hạn như hai E của Bart.

Vì vậy, hiện tại tôi sẽ sử dụng câu lệnh sau để nhận kết quả này, liên quan đến hai truy vấn phụ phụ thuộc. Công trình này tuyệt vời:

SELECT 
    CONCAT(
     '<users>', 
      IFNULL(
       GROUP_CONCAT(
        '<user>', 
         '<id><![CDATA[', 
          REPLACE(u.id,']]>',']]]]><![CDATA[>'), 
         ']]></id>', 
         '<name><![CDATA[', 
          REPLACE(u.name,']]>',']]]]><![CDATA[>'), 
         ']]></name>', 
         '<grades>', 
          (
           SELECT 
            IFNULL(
             GROUP_CONCAT(
              '<grade><![CDATA[', 
               REPLACE(g.grade,']]>',']]]]><![CDATA[>'), 
              ']]></grade>' 
              SEPARATOR '' 
             ), 
            '') 
           FROM 
            grades g 
           WHERE 
            g.userid = u.id 
          ), 
         '</grades>', 
         '<toys>', 
          (
           SELECT 
            IFNULL(
             GROUP_CONCAT(
              '<toys><![CDATA[', 
               REPLACE(t.toy,']]>',']]]]><![CDATA[>'), 
              ']]></toys>' 
              SEPARATOR '' 
             ), 
            '') 
           FROM 
            toys t 
           WHERE 
            t.userid = u.id 
          ), 
         '</toys>', 
        '</user>' 
        SEPARATOR '' 
       ), 
       '' 
      ), 
     '</users>' 
    ) 
FROM 
    users u 
WHERE 
    u.name = 'Bart' or u.name = 'Lisa' 
; 

Bây giờ bạn có thể nhận thấy, đây là một truy vấn khá lớn và xấu, làm đau mắt khi đọc. Việc duy trì một truy vấn như vậy rất khó. Nếu tôi sẽ có chức năng tôi XMLify và CDATAify, tôi chỉ đơn giản có thể viết này để thay thế:

SELECT 
    XMLify('users',(
     XMLify('user',(
      SELECT 
       CDATAify(u.id) as id, 
       CDATAify(u.name) as name, 
       XMLify('grade',(
        SELECT 
         CDATAify(g.grade) as grade 
        FROM 
         grades g 
        where 
         g.userid = u.id 
       )) AS grades, 
       XMLify('toys',(
        SELECT 
         CDATAify(t.toy) as toy 
        FROM 
         toys t 
        where 
         t.userid = u.id 
       )) AS grades 
      FROM 
       users u 
      WHERE 
       u.name = 'Bart' or u.name = 'Lisa' 
     )) 
    )) 
; 

EDIT:

Như đã đề cập trong các ý kiến ​​của N.B., có một repository on Github, có thể giữ tất cả tôi cần. Tuy nhiên tôi đã dành vài ngày bây giờ chỉ cố gắng để có được điều này để làm việc trên hệ thống của tôi, mà không thành công. Bất kỳ câu trả lời nào nắm giữ từng bước làm thế nào để cài đặt trên máy chủ MySQL 5.5 64 bit của tôi chạy trên Windows cũng được chấp nhận.

Xin lưu ý rằng tôi không có kinh nghiệm về việc tạo, makefiles, v.v. Vì vậy, hãy giải thích kỹ lưỡng.

+0

Vâng, nó xuất hiện [điều này sẽ được chính xác những gì bạn muốn] (https://github.com/mysqludf/lib_mysqludf_xml#readme). Đó là vấn đề cho dù bạn đã chọn con đường đúng mặc dù, nhìn thấy điều duy nhất bạn đang thiếu là tên trường. –

+0

@ N.B. Tôi đã dành vài ngày để làm việc đó, nhưng tôi vẫn thất bại. Tôi đã thử sao chép lib_mysqludf_xql.dll như được cung cấp trong thư mục 'win' trực tiếp vào 'MySQL Server 5.5/lib/plugin' của tôi và chạy installdb.sql, nhưng tôi tiếp tục nhận được 'ERROR 1126 (HY000): Không thể mở chia sẻ thư viện 'lib_mysqludf_xql.dll' (errno: 193) '. Tôi cũng muốn biên dịch DLL của riêng mình, nhưng dù tôi có làm gì đi nữa, tôi vẫn thất bại. Tôi đã thử bằng cách sử dụng Windows SDK, CMake, Cygwin, nhưng có vẻ như tôi chỉ không biết làm thế nào để tạo .dll của riêng tôi. Tôi có MySQL 5.5 64 bit trên Windows, giống như trên máy chủ của tôi. Điều này không thể thay đổi.) –

+0

[Kiểm tra liên kết này, khắc phục sự cố phần] (https://github.com/dtrebbien/lib_mysqludf_str/blob/master/README.win_x64.txt) - Tôi chưa bao giờ sử dụng MySQL trên Windows vì vậy tôi không một sự trợ giúp nhiều ở đó nhưng nó có thể là bạn hoặc có phân phối sai C++ hoặc MySQL có một thư mục plugin khác nhau. 'SHOW VARIABLES LIKE '% plugin%';' sẽ hiển thị nơi nó cố gắng tải các plugin từ đó. Khác với điều này, tôi không biết tôi có thể giúp đỡ nhiều hơn bao nhiêu:/ –

Trả lời

1

x, ngay hôm nay tôi tìm thấy câu hỏi này, tôi chỉ hy vọng trả lời câu hỏi này không quá muộn và nếu quá muộn, có thể nó sẽ giúp người khác.

Nguyên nhân MySql không cho phép thực hiện truy vấn động trên các hàm hoặc trình kích hoạt tôi chỉ chọn triển khai thủ tục được lưu trữ.

DELIMITER // 
DROP PROCEDURE IF EXISTS XMLify// 
CREATE PROCEDURE XMLify(IN wraper VARCHAR(100), IN expr VARCHAR(1000)) 
LANGUAGE SQL NOT DETERMINISTIC READS SQL DATA SQL SECURITY INVOKER 
BEGIN 
    DECLARE done INT DEFAULT FALSE; 
    DECLARE col_name VARCHAR(255); 
    DECLARE cur1 CURSOR FOR 
    SELECT 
     column_name 
    FROM 
     information_schema.columns 
    WHERE 
     table_schema = 'test' AND /*Name of the database (schema)*/ 
     table_name = 'temp' AND 
     column_name <> 'c4l5mn'; 
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; 

    DROP TABLE IF EXISTS temp; 
    SET @SQL = CONCAT('CREATE TABLE temp (c4l5mn TINYINT NOT NULL DEFAULT ''1'') AS ', expr); 
    PREPARE stmt1 FROM @SQL; 
    EXECUTE stmt1; 
    DEALLOCATE PREPARE stmt1; 

    OPEN cur1; 
    SET col_name = ''; 
    SET @SQL = ''; 
    read_loop: LOOP 
     FETCH cur1 INTO col_name; 
     IF done THEN 
      LEAVE read_loop; 
     END IF; 
     SET @SQL = CONCAT(@SQL, '<', col_name, '>'', ', col_name, ', ''</', col_name, '>'); 
    END LOOP; 
    CLOSE cur1; 
    SET @SQl = CONCAT('SELECT GROUP_CONCAT(CONCAT(''<', wraper, '>', @SQL, '</', wraper, '>'') SEPARATOR '''') row FROM temp GROUP BY c4l5mn'); 
    PREPARE stmt1 FROM @SQL; 
    EXECUTE stmt1; 
    DEALLOCATE PREPARE stmt1; 
    DROP TABLE IF EXISTS temp; 
END// 
DELIMITER ; 

đó là nó, bây giờ bạn có thể gọi nó giống như

CALL XMLify('foo', 'SELECT 1 as `a`, 2 as `b` UNION SELECT 3, 4'); 

Và nó sẽ trở lại

<foo><a>1</a><b>2</b></foo><foo><a>3</a><b>4</b></foo> 

Gọi

CALL XMLify('foo', 'SELECT 1 as a, 2 as b, 3 as c UNION SELECT 4, 5, 6'); 

Sẽ trở lại

<foo><a>1</a><b>2</b><c>3</c></foo><foo><a>4</a><b>5</b><c>6</c></foo> 

Tôi chỉ hy vọng nó sẽ giúp Greetings

Các vấn đề liên quan