2010-11-17 23 views
7

Tôi coi mình khá giỏi trong việc hiểu và thao tác ngôn ngữ C-ish; nó không phải là một vấn đề đối với tôi để đưa ra một thuật toán và thực hiện nó trong bất kỳ ngôn ngữ C-ish.Cách cấu trúc để xây dựng một truy vấn MySQL là gì?

Tôi gặp khó khăn to lớn khi viết các truy vấn SQL (trong trường hợp cụ thể của tôi, MySQL). Đối với các truy vấn rất đơn giản, nó không phải là một vấn đề, nhưng đối với các truy vấn phức tạp, tôi trở nên thất vọng không biết bắt đầu từ đâu. Việc đọc tài liệu MySQL là khó khăn, chủ yếu là do mô tả cú pháp và giải thích không được tổ chức rất tốt.

Ví dụ, tài liệu SELECT là tất cả trên bản đồ: nó bắt đầu với những gì trông giống như psuedo-BNF, nhưng sau đó (vì văn bản cho mô tả tổng hợp không thể nhấp ... như select_expr) bài tập bực bội này khi cố gắng tự xâu cú pháp bằng cách mở một số cửa sổ trình duyệt.

Đủ can đảm.

Tôi muốn biết mọi người, từng bước, bắt đầu xây dựng một truy vấn MySQL phức tạp như thế nào. Đây là một ví dụ cụ thể. Tôi có ba bảng dưới đây. Tôi muốn SELECT một tập hợp các hàng với các đặc điểm sau:

Từ bảng userInfouserProgram, tôi muốn chọn userName, isApproved, và modifiedTimestamp lĩnh vực và UNION chúng thành một bộ. Từ tập này, tôi muốn ORDER bằng cách modifiedTimestamp lấy MAX(modifiedTimestamp) cho mọi người dùng (nghĩa là chỉ nên có một hàng có userName và dấu thời gian được liên kết với tên người dùng đó càng cao càng tốt).

Từ bảng user, tôi muốn để phù hợp với firstNamelastName được liên kết với các userName để nó trông giống như sau:

+-----------+----------+----------+-------------------+ 
| firstName | lastName | userName | modifiedTimestamp | 
+-----------+----------+----------+-------------------+ 
| JJ  | Prof  | jjprofUs |  1289914725 | 
| User  | 2  | user2 |  1289914722 | 
| User  | 1  | user1 |  1289914716 | 
| User  | 3  | user3 |  1289914713 | 
| User  | 4  | user4 |  1289914712 | 
| User  | 5  | user5 |  1289914711 | 
+-----------+----------+----------+-------------------+ 

Gần nhất tôi nhận được là một truy vấn mà trông giống như này:

(SELECT firstName, lastName, user.userName, modifiedTimestamp 
FROM user, userInfo 
WHERE user.userName=userInfo.userName) 

UNION 

(SELECT firstName, lastName, user.userName, modifiedTimestamp 
FROM user, userProgram 
WHERE user.userName=userProgram.userName) 

ORDER BY modifiedTimestamp DESC; 

Tôi cảm thấy mình khá thân thiết nhưng tôi không biết phải đi đâu từ đây hoặc ngay cả khi tôi đang nghĩ về điều này đúng cách.

> user 
+--------------------+--------------+------+-----+---------+-------+ 
| Field    | Type   | Null | Key | Default | Extra | 
+--------------------+--------------+------+-----+---------+-------+ 
| userName   | char(8)  | NO | PRI | NULL |  | 
| firstName   | varchar(255) | NO |  | NULL |  | 
| lastName   | varchar(255) | NO |  | NULL |  | 
| email    | varchar(255) | NO | UNI | NULL |  | 
| avatar    | varchar(255) | YES |  | ''  |  | 
| password   | varchar(255) | NO |  | NULL |  | 
| passwordHint  | text   | YES |  | NULL |  | 
| access    | int(11)  | NO |  | 1  |  | 
| lastLoginTimestamp | int(11)  | NO |  | -1  |  | 
| isActive   | tinyint(4) | NO |  | 1  |  | 
+--------------------+--------------+------+-----+---------+-------+ 

> userInfo 
+-------------------+------------+------+-----+---------+-------+ 
| Field    | Type  | Null | Key | Default | Extra | 
+-------------------+------------+------+-----+---------+-------+ 
| userName   | char(8) | NO | MUL | NULL |  | 
| isApproved  | tinyint(4) | NO |  | 0  |  | 
| modifiedTimestamp | int(11) | NO |  | NULL |  | 
| field    | char(255) | YES |  | NULL |  | 
| value    | text  | YES |  | NULL |  | 
+-------------------+------------+------+-----+---------+-------+ 

> userProgram 
+-------------------+--------------+------+-----+---------+-------+ 
| Field    | Type   | Null | Key | Default | Extra | 
+-------------------+--------------+------+-----+---------+-------+ 
| userName   | char(8)  | NO | PRI | NULL |  | 
| isApproved  | tinyint(4) | NO | PRI | 0  |  | 
| modifiedTimestamp | int(11)  | NO |  | NULL |  | 
| name    | varchar(255) | YES |  | NULL |  | 
| address1   | varchar(255) | YES |  | NULL |  | 
| address2   | varchar(255) | YES |  | NULL |  | 
| city    | varchar(50) | YES |  | NULL |  | 
| state    | char(2)  | YES | MUL | NULL |  | 
| zip    | char(10)  | YES |  | NULL |  | 
| phone    | varchar(25) | YES |  | NULL |  | 
| fax    | varchar(25) | YES |  | NULL |  | 
| ehsChildren  | int(11)  | YES |  | NULL |  | 
| hsChildren  | int(11)  | YES |  | NULL |  | 
| siteCount   | int(11)  | YES |  | NULL |  | 
| staffCount  | int(11)  | YES |  | NULL |  | 
| grantee   | varchar(255) | YES |  | NULL |  | 
| programType  | varchar(255) | YES |  | NULL |  | 
| additional  | text   | YES |  | NULL |  | 
+-------------------+--------------+------+-----+---------+-------+ 
+1

Điều này hoàn toàn không liên quan đến jQuery. Đã xóa thẻ. – casablanca

+0

Nếu bạn muốn tìm hiểu SQL, tài liệu của việc thực hiện một cơ sở dữ liệu bằng cách sử dụng nó không phải là tài liệu tốt. Tài liệu này được viết cho người đã biết SQL một cách hợp lý. Vì vậy, bạn nên tìm một số tài liệu để học SQL thay thế. – Guffa

Trả lời

1

Đối với những gì tôi hiểu từ câu hỏi của bạn, bạn dường như cần một truy vấn tương quan, trong đó sẽ trông như thế này:

(SELECT firstName, lastName, user.userName, modifiedTimestamp 
FROM user, userInfo ui1 
WHERE user.userName=userInfo.userName 
AND modifiedtimestamp=(select max(modifiedtimestamp) from userInfo ui2 where ui1.userName=ui2.userName)) 

UNION 

(SELECT firstName, lastName, user.userName, modifiedTimestamp 
FROM user, userProgram up1 
WHERE user.userName=userProgram.userName 
AND modifiedtimestamp=(select max(modifiedtimestamp) from userProgram up2 where up1.userName=up2.userName)) 
ORDER BY modifiedTimestamp DESC; 

Vì vậy, tôi tiến hành để có được kết quả này? Khóa là: thể hiện rõ ràng thông tin bạn muốn truy xuất, mà không cần dùng các phím tắt về tinh thần.

Bước 1: Chọn các trường tôi cần trong các bảng khác nhau trong cơ sở dữ liệu của tôi. Đó là những gì giữa SELECT và FROM. Có vẻ hiển nhiên, nhưng nó trở nên ít rõ ràng hơn khi nói đến hàm tổng hợp như tổng hoặc đếm. Trong trường hợp đó, bạn phải nói, ví dụ "Tôi cần đếm số dòng trong userInfo cho mỗi firstName". Xem bên dưới trong GROUP BY.

Bước 2: Biết trường bạn cần, ghi các kết nối giữa các bảng tương ứng khác nhau. Thật dễ dàng ...

Bước 3: Thể hiện điều kiện của bạn.Nó có thể dễ dàng, giống như nếu bạn muốn dữ liệu từ người dùng cho userName = "RZEZDFGBH", hoặc phức tạp hơn, như trong trường hợp của bạn: cách xây dựng nó để bạn có thể hoàn thành công việc, nếu bạn chỉ muốn sửa đổi lần gần đây nhất, là "sao cho biến được sửa đổi bằng với biến đổi gần đây nhất" (đó là nơi bạn có thể dễ dàng lấy một lối tắt tâm thần và bỏ lỡ điểm)

Bước 4: Nếu bạn có tổng hợp, đã đến lúc đặt câu lệnh GROUP BY. Ví dụ, nếu bạn đếm tất cả các dòng trong UserInfo cho mỗi firstName, bạn sẽ viết "GROUP BY firstName":

SELECT firstName,count(*) FROM userInfo GROUP BY firstName 

này cung cấp cho bạn số lượng các mục trong bảng cho mỗi firstName khác nhau.

Bước 5: CÓ điều kiện. Đây là những điều kiện trên tổng hợp. Trong ví dụ trước, nếu bạn chỉ muốn dữ liệu cho firstName có hơn 5 dòng trong bảng, bạn có thể viết SELECT firstName,count(*) FROM userInfo GROUP BY firstName HAVING count(*)>5

Bước 6: Sắp xếp theo ORDER BY. Khá dễ dàng ...

Đó chỉ là một bản tóm tắt ngắn. Có nhiều, nhiều hơn nữa để khám phá, nhưng nó sẽ là quá dài để viết toàn bộ một khóa học SQL ở đây ... Hy vọng nó giúp, mặc dù!

+0

Điều này không thực sự trả lời câu hỏi của tôi. Tôi không quan tâm nhiều đến câu trả lời cho ví dụ của tôi. Tôi quan tâm đến _how_ bạn đã đến câu trả lời đó. Nếu bạn có thể nhìn vào mô tả của tôi và sau đó chỉ cho tôi quá trình suy nghĩ để xây dựng truy vấn, điều đó thật tuyệt vời. – Avery

+0

Vấn đề là: Tôi không hoàn toàn chắc chắn mã của tôi làm những gì bạn muốn, bởi vì câu hỏi của bạn là một chút không rõ ràng. Giả sử nó là và những gì bạn đang tìm kiếm, bắt đầu với kết quả truy vấn của bạn, chỉ trả lại dòng tương ứng với biến đổi mới nhấtTimestamp cho mỗi người dùng. Điều này có đúng không? Tôi sẽ sửa đổi câu trả lời của tôi. –

0

Bạn không thể xây dựng sql mà không hiểu các dữ liệu trong các bảng và kết quả logic cần thiết. Không có nền tảng cho dữ liệu nào mà các bảng có thể trông giống và có ý nghĩa và mô tả kết quả bạn đang cố thu thập không có ý nghĩa với tôi vì vậy tôi sẽ không mạo hiểm đoán.

Về điểm sau ... hiếm khi bạn muốn một liên kết giá trị dấu thời gian cho nhiều nguồn. Nói chung khi kết quả như vậy được thu thập, nó thường cho một số loại kiểm toán/truy tìm. Tuy nhiên, khi bạn loại bỏ tất cả thông tin về nguồn gốc của dấu thời gian và chỉ cần tính toán tối đa bạn có ... thì chính xác thì sao?

Dù sao, một hoặc nhiều ví dụ về dữ liệu và đầu ra mong muốn và có thể có điều gì đó về ứng dụng và whys là điều cần thiết để làm cho bản thân bạn rõ ràng.

Trong phạm vi tôi sẽ thực hiện bất kỳ dự đoán về hình dạng của tuyên bố cuối cùng của bạn, (giả sử công việc của bạn vẫn sẽ có để có được một dấu thời gian tối đa duy nhất cho mỗi người dùng) nó rằng nó sẽ giống như thế này:

select u.firstname, u.lastname, user_max_time.userName, user_max_time.max_time 
from users u, 
(select (sometable).userName, max((sometable).(timestamp column)) 
from (data of interest) 
group by (sometable).userName) user_max_time 
where u.userName = user_max_time.userName 
order by max_time desc; 

Nhiệm vụ của bạn ở đây sẽ là thay thế() s bên trong vùng chọn user_max_time bằng thứ gì đó có ý nghĩa và ánh xạ tới yêu cầu của bạn. Về phương pháp tiếp cận chung đối với sql phức tạp, đề xuất chính là xây dựng truy vấn từ các lựa chọn con trong cùng trở lại (kiểm tra dọc theo cách để đảm bảo hiệu suất là ok và bạn không cần các bảng trung gian).

Dù sao, nếu bạn gặp sự cố và có thể quay lại với các ví dụ, sẽ sẵn lòng trợ giúp.

Chúc mừng, Bến

+0

bạn có thể định dạng mã trên SO bằng cách đánh dấu nó và nhấp vào nút '101'. –

+0

Vâng, tôi nhận ra tầm quan trọng của cấu trúc bảng mà tôi đăng là mờ đục. Chỉ cần mang thêm một chút ánh sáng: cho ứng dụng của chúng ta, chúng ta sẽ luôn có userProgram nhưng các mục trong userInfo thì linh hoạt. Lý do chúng tôi kết hợp chúng là chúng tôi muốn cập nhật lần cuối đã xảy ra, cho dù đó là tổng hợp của userProgram hoặc một phần tử trong userInfo. – Avery

1

Như f00 nói, nó đơn giản (r) nếu bạn nghĩ về các dữ liệu về bộ.

Một trong những vấn đề với câu hỏi là giá trị mong đợi không khớp với yêu cầu đã nêu - mô tả đề cập đến cột isApproved, nhưng điều này không xuất hiện ở bất kỳ đâu trong truy vấn hoặc đầu ra mong đợi.

Điều này minh họa là bước đầu tiên để viết truy vấn là có ý tưởng rõ ràng về những gì bạn muốn đạt được. Vấn đề lớn hơn với câu hỏi là nó không được mô tả rõ ràng - thay vào đó, nó chuyển từ bảng mẫu đầu ra mong đợi (sẽ hữu ích hơn nếu chúng ta có các mẫu dữ liệu đầu vào tương ứng) vào mô tả làm thế nào bạn có ý định đạt được nó.

Như tôi đã hiểu, những gì bạn muốn xem là danh sách người dùng (theo tên người dùng, với họ và tên liên quan), cùng với lần cuối cùng bất kỳ bản ghi được liên kết nào được sửa đổi trên userInfo hoặc userProgram những cái bàn.

(Nó không phải là rõ ràng cho dù bạn muốn nhìn thấy những người dùng không có hoạt động liên quan trên một trong các bảng khác - truy vấn cung cấp của bạn ngụ ý không, nếu không tham gia sẽ là bên ngoài tham gia.)

Vì vậy, bạn muốn có một danh sách người dùng (username, với những cái tên đầu tiên và cuối cùng của họ liên quan):

SELECT firstName, lastName, userName 
FROM user 

cùng với một danh sách các lần so với hồ sơ đã được sửa đổi lần cuối:

SELECT userName, MAX(modifiedTimestamp) 

...

trên một trong hai UserInfo hoặc userProgram bảng:

...

FROM 
(SELECT userName, modifiedTimestamp FROM userInfo 
UNION ALL 
SELECT userName, modifiedTimestamp FROM userProgram 
) subquery -- <- this is an alias 

...

bởi userName:

...

group by userName 

Hai bộ dữ liệu cần phải được liên kết bởi userName của họ - vì vậy truy vấn chính thức trở thành:

SELECT user.firstName, user.lastName, user.userName, 
     MAX(subquery.modifiedTimestamp) last_modifiedTimestamp 
FROM user 
JOIN 
(SELECT userName, modifiedTimestamp FROM userInfo 
UNION ALL 
SELECT userName, modifiedTimestamp FROM userProgram 
) subquery 
ON user.userName = subquery.userName 
GROUP BY user.userName 

Trong hầu hết các phiên bản của SQL, truy vấn này sẽ trả về một lỗi như user.firstNameuser.lastName không nằm trong mệnh đề GROUP BY và cũng không được tóm tắt. MySQL cho phép cú pháp này - trong các SQL khác, vì các trường đó phụ thuộc vào chức năng trên userName, thêm MAX ở trước mỗi trường hoặc thêm chúng vào nhóm sẽ đạt được kết quả tương tự.

Một vài điểm bổ sung:

  • UNION và UNION ALL không giống hệt nhau - cựu loại bỏ bản sao trong khi sau này không; điều này làm cho bộ xử lý chuyên sâu hơn trước đây. Vì các bản sao sẽ bị xóa theo nhóm, tốt hơn nên sử dụng UNION ALL.
  • Nhiều người sẽ viết truy vấn này khi người dùng tham gia vào userInfo UNIONED ALL với người dùng tham gia vào chương trình người dùng - điều này là do nhiều công cụ SQL có thể tối ưu hóa loại truy vấn này hiệu quả hơn. Tại thời điểm này, điều này thể hiện tối ưu hóa sớm.
1

Có rất nhiều thứ tuyệt vời ở đây. Cảm ơn những người đã đóng góp. Đây là tóm tắt nhanh về những điều tôi thấy hữu ích cũng như một số suy nghĩ bổ sung trong việc kết nối các chức năng xây dựng để xây dựng các truy vấn. Tôi ước gì tôi có thể tặng cho tất cả mọi người huy hiệu/điểm xứng đáng của SO, nhưng tôi nghĩ rằng chỉ có thể có một (câu trả lời) vì vậy tôi chọn Traroth dựa trên tổng số điểm và tính hữu ích cá nhân.

Một hàm có thể được hiểu là ba phần: đầu vào, quy trình, đầu ra. Một truy vấn có thể được hiểu tương tự. Hầu hết các truy vấn tìm kiếm một cái gì đó như thế này:

SELECT stuff FROM data WHERE data is like something 
  • Phần SELECT là đầu ra. Có một số khả năng định dạng đầu ra ở đây (tức là sử dụng AS)

  • Phần FROM là đầu vào. Dữ liệu đầu vào nên được xem như một nhóm dữ liệu; bạn sẽ muốn làm điều này càng cụ thể càng tốt, bằng cách sử dụng một loạt các phép nối và các truy vấn con phù hợp.

  • Phần WHERE giống như quy trình, nhưng có nhiều trùng lặp với phần FROM. Cả hai phần FROMWHERE có thể làm giảm nhóm dữ liệu một cách thích hợp bằng nhiều điều kiện khác nhau để lọc ra dữ liệu không mong muốn (hoặc chỉ bao gồm dữ liệu mong muốn). Phần WHERE cũng có thể giúp định dạng đầu ra.

Đây là cách tôi bị phá vỡ các bước:

  1. Bắt đầu với suy nghĩ về những gì đầu ra của bạn trông như thế nào. Công cụ này đi vào phần SELECT.

  2. Tiếp theo, bạn muốn xác định tập hợp dữ liệu mà bạn muốn làm việc. Traroth lưu ý: "Biết lĩnh vực bạn cần, viết các kết nối giữa các bảng tương ứng khác nhau. Đó là một cách dễ dàng ..." Nó phụ thuộc vào ý bạn là "dễ". Nếu bạn chưa quen với việc viết các truy vấn, có thể bạn sẽ chỉ mặc định để viết các kết nối bên trong (như tôi đã làm). Đây không phải lúc nào cũng là cách tốt nhất để đi. http://en.wikipedia.org/wiki/Join_(SQL) là một nguồn tài nguyên tuyệt vời để hiểu các loại tham gia khác nhau có thể.

  3. Là một phần của bước trước, hãy nghĩ về các phần nhỏ hơn của tập dữ liệu đó và xây dựng bộ dữ liệu hoàn chỉnh mà bạn quan tâm. cách thức. Tương tự như vậy, bạn có thể viết truy vấn phụ. Một mẹo lớn từ Mark Bannister trong việc tạo ra một truy vấn con và sử dụng một ALIAS. Bạn sẽ phải cấu hình lại đầu ra của bạn để sử dụng bí danh này, nhưng điều này là khá quan trọng.

  4. cuối, bạn có thể sử dụng các phương pháp khác nhau để pare xuống bộ dữ liệu của bạn, loại bỏ các dữ liệu mà bạn không quan tâm đến

Một cách để suy nghĩ về những dữ liệu bạn đang hoạt động trên là một người khổng lồ 2- D ma trận: JOIN s làm cho chiều ngang lớn hơn, UNION s làm cho chiều rộng lớn hơn theo chiều dọc.Tất cả các bộ lọc khác được thiết kế để làm cho ma trận này nhỏ hơn để phù hợp với đầu ra của bạn. Tôi không biết nếu có một "chức năng" tương tự để JOIN, nhưng UNION chỉ là thêm đầu ra của hai chức năng với nhau.

Tôi nhận ra, tuy nhiên, có rất nhiều cách để tạo truy vấn KHÔNG giống như viết hàm. Ví dụ: bạn có thể xây dựng và chia nhỏ bộ dữ liệu của mình trong cả hai khu vực FROMWHERE. Điều quan trọng đối với tôi là hiểu sự tham gia và tìm hiểu cách tạo truy vấn con bằng cách sử dụng bí danh.

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