iT邦幫忙

0

MySql Select 一問

  • 分享至 

  • xImage

因為實在...試不出來,想請教站上大大...

我需要同時抓兩個資料表,並希望結果是能顯示最後更新的資料,

資料表如下:
資料表hos_main
資料欄hos_id, hos_name

B表 hos_image
資料欄 hos_img_id, hos_id, hos_img_url, hos_img_upload_date

從A表中要取出 hos_name
從B表中要取出 hos_img_url

這樣的語法,可work

這樣的語法,也可work

可是...紅色指向那一列的資料,卻不是跟著右邊欄位連動的...

早上九點試到現在,脖子都硬了...

不知那位大大能指點一下迷津...謝謝您。哭

哭

看更多先前的討論...收起先前的討論...
總裁 iT邦好手 1 級 ‧ 2013-04-29 16:25:30 檢舉
暈我連題目都看不懂....Orz海綿寶寶,交給你了....讚
拜託
題目那麼簡單....

是答案比較難
Orz
總裁 iT邦好手 1 級 ‧ 2013-04-29 17:18:54 檢舉
我...噎到都看不懂...Orz
sunallen提到:
早上九點試到現在,脖子都硬了...


想不到還有這等功效
如果是泰大
一定會想辦法加以改良
發揮在該用的地方
汗
雖然各位大大已經有了正確的詳解

但是基於小弟的鑽牛角尖(無聊的一股想解題的衝勁Orz)

在這分享一下我想出來的SQL語法

select m.hos_name, max(i.hos_img_url),max(i.hos_img_upload_date)
from hos_main m,hos_image i 
where m.hos_id like i.hos_id
group by m.hos_name
order by max(i.hos_img_upload_date) desc;

這是小弟用手邊的accessDB測試用的模型(抱歉>< 懶得架Mysql測..其實很久沒用mysql...Orz)
表1

表2

我先做了兩表連結用法如inner join得到查詢1,查詢1是用來驗證我最後的答案是否是我預期想要的答案
查詢1
最後我用下列查詢語法得到我想要的答案查詢2
select m.hos_name, max(i.hos_img_url),max(i.hos_img_upload_date)
from hos_main m,hos_image i 
where m.hos_id like i.hos_id
group by m.hos_name
order by max(i.hos_img_upload_date) desc;

查詢2(Done)


最後歸納一下我的語法的優點,請各位先進指導XD
1.執行查詢時兩張表各scan一次,複雜度O(1),所以效能比較好(I guess!?)
2.圖片欄位可以接受不同檔名的檔案,不會讓查詢因為上傳圖片檔名不同而出現重複資料。
隱約中看見Bug.....哀..
將max改成用last,最新的資料,bug就從心中移除了...@@
select m.hos_name, last(i.hos_img_url),last(i.hos_img_upload_date)  
from hos_main m,hos_image i   
where m.hos_id like i.hos_id  
group by m.hos_name  
order by last(i.hos_img_upload_date) desc;  
另外附上一組,很無恥的直接用Access拉出來的語法...><
SELECT hos_main.hos_name, Last(hos_image.hos_img_url) AS hos_img_url之最後一筆, Last(hos_image.hos_img_upload_date) AS hos_img_upload_date之最後一筆
FROM hos_image INNER JOIN hos_main ON hos_image.hos_id = hos_main.hos_id
GROUP BY hos_main.hos_name
ORDER BY Last(hos_image.hos_img_upload_date) DESC;
最後附上小畫家所提供的最後解...Orz
http://stackoverflow.com/questions/5495913/can-i-use-aggregation-function-last-in-mysql
最後我發現mysql沒有last指令
所以只能用子查詢><
語法晚點再想一下
下面的查詢,我做了一些新增,與上面的表內容資料有不一致的地方,稍做一下說明:
我將表hos_main新增兩筆資料作驗證用
因為"C:\Intel\Logs\11.jpg"才是最後一筆資料
如果查詢出現欄位"C:\Intel\Logs\12.jpg"是最後一筆資料,就是語法錯誤
出現"C:\Intel\Logs\11.jpg"則成功

不使用last的方式查詢
step1:先將最後更新的欄位從hos_image表取出
select hos_id,hos_img_url,hos_img_upload_date    
from hos_image i 
where i.hos_img_upload_date=
(
select max(hos_img_upload_date)
from hos_image
where hos_id=i.hos_id
group by hos_id
) ;


step2:合併hos_image和hos_main兩張表
select m.hos_name,i.hos_img_url,i.hos_img_upload_date
from hos_main m,   
前面那個查詢子句 i
where m.hos_id = i.hos_id
order by i.hos_img_upload_date desc;

檢視全部程式碼
select m.hos_name,i.hos_img_url,i.hos_img_upload_date
from hos_main m,   
(
select hos_id,hos_img_url,hos_img_upload_date    
from hos_image i 
where i.hos_img_upload_date=
(
select max(hos_img_upload_date)
from hos_image
where hos_id=i.hos_id
group by hos_id
)
) i
where m.hos_id = i.hos_id
order by i.hos_img_upload_date desc;

最後心得:
程式語法還是很長,不容易讀,不知道使用last功能的效能,是不是跟這個語法寫出來的狀況一樣差
用了2個子查詢,時間複雜度O(N*N),如果只是用在一般資料維護,效能影響不大,如果是用在給大眾查詢,那人一多系統的負擔會非常大。
恩~針對這種類型的查詢
如果真的考慮到效能問題,可以使用建View的方式,不要讓使用者直接查詢資料庫,效能一級棒XD
好吧~剛剛又發現View裡面不能有子查詢~所以View不能用,那退而求其次,固定一小時做一張表格出來供多人查詢用。
CREATE TABLE mytable (select ....上述查詢語法);
外獅佬 iT邦大師 1 級 ‧ 2013-05-02 16:19:20 檢舉
你累了嗎?...不需要硬要回答..失神
唉唷~研究嘛~~別這樣~
就說了一股衝勁~
搞得我頭滿痛的~~
可能要休息好幾天...><
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
14
一級屠豬士
iT邦大師 1 級 ‧ 2013-04-29 17:12:38
最佳解答
&lt;pre class="c" name="code">CREATE TABLE hos_main(
hos_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
hos_name VARCHAR(30) NOT NULL);

INSERT INTO hos_main(hos_name) VALUES
('我是天字一號房'), ('我是地字一號房'),
('我是玄字一號房'), ('我是黃字一號房');

CREATE TABLE hos_image(
hos_img_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
hos_id INT UNSIGNED NOT NULL,
hos_img_url VARCHAR(120),
hos_img_upload_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY(hos_id) REFERENCES hos_main(hos_id));

INSERT INTO hos_image(hos_id, hos_img_url, hos_img_upload_date) VALUES
(1, "D:\\img\\天字一號房\\sky001.jpg", '2013-4-27 18:37:54'),
(1, "D:\\img\\天字一號房\\sky002.jpg", '2013-4-27 19:58:27'),
(2, "D:\\img\\地字一號房\\ground001.jpg", '2013-4-27 18:39:04'),
(2, "D:\\img\\地字一號房\\ground002.jpg", '2013-4-27 20:04:35'),
(3, "D:\\img\\玄字一號房\\dark001.jpg", '2013-4-27 21:25:24'),
(3, "D:\\img\\玄字一號房\\dark002.jpg", '2013-4-28 16:57:23'),
(4, "D:\\img\\黃字一號房\\yellow001.jpg", '2013-4-27 22:17:25'),
(4, "D:\\img\\黃字一號房\\yellow002.jpg", '2013-4-28 13:14:42');

-- 找出每一個房間最新更新圖形的房間名稱,時間與圖形url
SELECT m.hos_name, j.hos_img_url, i.mdate AS '我是最新的圖片更新時間'
FROM hos_main m 
JOIN (SELECT hos_id, MAX(hos_img_upload_date) AS mdate
       FROM hos_image
       GROUP BY hos_id) i
ON m.hos_id = i.hos_id
JOIN hos_image j
ON i.mdate = j.hos_img_upload_date
ORDER BY m.hos_id;

+-----------------------+--------------------------------------+-----------------------------------+
| hos_name              | hos_img_url                          | 我是最新的圖片更新時間            |
+-----------------------+--------------------------------------+-----------------------------------+
| 我是天字一號房        | D:\img\天字一號房\sky002.jpg         | 2013-04-27 19:58:27               |
| 我是地字一號房        | D:\img\地字一號房\ground002.jpg      | 2013-04-27 20:04:35               |
| 我是玄字一號房        | D:\img\玄字一號房\dark002.jpg        | 2013-04-28 16:57:23               |
| 我是黃字一號房        | D:\img\黃字一號房\yellow002.jpg      | 2013-04-28 13:14:42               |
+-----------------------+--------------------------------------+-----------------------------------+
SunAllen iT邦研究生 1 級 ‧ 2013-04-29 17:22:45 檢舉

謝謝 小雨 大大...哭哭

8
老鷹(eagle)
iT邦高手 1 級 ‧ 2013-04-29 16:43:14

試試看這個 UNION
不然就是用 JOIN

看更多先前的回應...收起先前的回應...

排序 在加 顯示一筆

太陽大 PHP+MYSQL
我可以推薦一本我學習的書,也是線上前輩推薦我的書籍,
徹底研究 PHP+MYSQL全能權威指南
上奇 出版社 作者 張亞飛

然後線上前輩說 如果可以先學物件導向~~!

SunAllen iT邦研究生 1 級 ‧ 2013-04-29 17:23:25 檢舉

謝謝 老鷹大大...如果我有時間,我一定會去買來看看哭哭

神啊~~請多給我一點時間Orz

總裁 iT邦好手 1 級 ‧ 2013-04-29 17:30:17 檢舉

Yes

12
外獅佬
iT邦大師 1 級 ‧ 2013-04-29 16:46:10

SQL裡頭的MAX、MIN之類的統計函數,用途是抓取特定欄位中的最大或最小值
並不會影響其他欄位的排序,所以,MAX不應該用在這裡
把查詢改一下...把MAX變成條件,應該就會是你要的查詢結果了...

&lt;pre class="c" name="code">
SELECT `hos_image_url`,MAX(`hos_image_upload_date`) AS `last_upload_date`,`hos_name`
FROM `hos_image`,`hos_main`
WHERE `hos_image`.`hos_image_upload_date`=MAX(`hos_image`.`hos_image_upload_date`)
AND `hos_main`.`hos_id`=`hos_image`.`hos_id`

比對hos_image_upload_date值等於最大值....

看更多先前的回應...收起先前的回應...
外獅佬 iT邦大師 1 級 ‧ 2013-04-29 16:47:34 檢舉

其實,太陽大自己寫的那個第一種寫法,應該就可以達到目的了...
利用我這種寫法,只是多拐了幾個彎...資料一多,會有效能上的問題。

外獅佬真強灑花

總裁 iT邦好手 1 級 ‧ 2013-04-29 16:56:35 檢舉

以目前太陽大民宿的規模,資料應該還不多....冷

SunAllen iT邦研究生 1 級 ‧ 2013-04-29 17:22:08 檢舉

謝謝L大大...哭哭

16
海綿寶寶
iT邦大神 1 級 ‧ 2013-04-29 17:09:16

我用的是最笨的方法
就是「再加一個Table」
看看合不合用

&lt;pre class="c" name="code">
SELECT *
FROM hos_main m, hos_image i,
(SELECT hos_id, MAX( hos_img_upload_date ) AS MaxDateTime
 FROM hos_image
 GROUP BY hos_id) x
WHERE m.hos_id=i.hos_id
  AND i.hos_id=x.hos_id
  AND i.hos_img_upload_date=x.MaxDateTime
看更多先前的回應...收起先前的回應...
SunAllen iT邦研究生 1 級 ‧ 2013-04-29 17:22:29 檢舉

謝謝 antijava 大大...哭哭

fillano iT邦超人 1 級 ‧ 2013-04-29 18:16:24 檢舉

剛剛想到,用sub query應該可以更簡單一點:

&lt;pre class="c" name="code">
SELECT * FROM (SELECT * FROM hos_image ORDER BY hos_img_upload_date DESC) a group by a.hos_id; 

既然GROUP BY預設取第一筆,那我先把資料用hos_img_upload_date降冪排序就可以。不過我這樣做sub query基本上是full table scan,效率應該很差就是了XD

再把hos_main加上去,就可以用inner join取得hos_name:

&lt;pre class="c" name="code">
SELECT b.hos_name, a.hos_img_url, a.hos_img_upload_date FROM (SELECT * FROM hos_image ORDER BY hos_img_upload_date DESC) a, hos_main b WHERE b.hos_id=a.hos_id GROUP BY a.hos_id;
fillano iT邦超人 1 級 ‧ 2013-04-29 20:11:53 檢舉

上網找了一下,看起來沒有其他比較好的方法...另外,排成一行有點難閱讀,我重排一下:

&lt;pre class="c" name="code">
SELECT 
  b.hos_name, a.hos_img_url, a.hos_img_upload_date 
FROM 
  (SELECT * FROM hos_image ORDER BY hos_img_upload_date DESC) a,
  hos_main b 
WHERE 
  b.hos_id=a.hos_id 
GROUP BY 
  a.hos_id;

fillano大大的答案更漂亮
讚

fillano提到:
GROUP BY預設取第一筆

這應該是 MySQL 才這樣吧
疑惑
今天才知道
臉紅

xnchan iT邦新手 5 級 ‧ 2013-04-30 14:12:26 檢舉

hos_main 超過一筆又如何,反正只是要顯示最後更新的資料,而不是每一條ID最後更新的資料

xnchan提到:
而不是每一條ID最後更新的資料

建議你去看看最佳解答的範例資料再下結論
落寞

xnchan iT邦新手 5 級 ‧ 2013-04-30 18:00:02 檢舉

antijava提到:
建議你去看看最佳解答的範例資料再下結論

那就只需可上GROUP BY就可以了啦,用SUB QUERY速度不會變慢嗎?

&lt;pre class="c" name="code">SELECT     
  a.hos_name, b.hos_img_url    
FROM     
  hos_main a, hos_image b    
WHERE     
  a.hos_id=b.hos_id     
ORDER BY     
  b.hos_img_upload_date DESC,a.hos_id 
GROUP BY
  a.hos_id 
LIMIT    
  1;    
xnchan iT邦新手 5 級 ‧ 2013-04-30 18:01:48 檢舉

抱歉,手快沒看清楚,應該是

&lt;pre class="c" name="code">
SELECT     
  a.hos_name, b.hos_img_url    
FROM     
  hos_main a, hos_image b    
WHERE     
  a.hos_id=b.hos_id     
GROUP BY
  a.hos_id 
ORDER BY     
  b.hos_img_upload_date DESC,a.hos_id 
LIMIT    
  1;  
&lt;pre class="c" name="code">
    SELECT       
      a.hos_name, b.hos_img_url      
    FROM       
      hos_main a, hos_image b      
    WHERE       
      a.hos_id=b.hos_id       
    GROUP BY  
      a.hos_id   
    ORDER BY       
      b.hos_img_upload_date DESC,a.hos_id   
    LIMIT      
      1;    
結果如:
+-----------------------+--------------------------------------+
| hos_name              | hos_img_url                          |
+-----------------------+--------------------------------------+
| 我是黃字一號房        | D:\img\黃字一號房\yellow001.jpg      |
+-----------------------+--------------------------------------+
xnchan iT邦新手 5 級 ‧ 2013-04-30 18:34:32 檢舉

恩恩,明白了

xnchan iT邦新手 5 級 ‧ 2013-04-30 18:38:14 檢舉

那如果這樣呢

&lt;pre class="c" name="code">
SELECT       
      a.hos_name, b.hos_img_url      
    FROM       
      hos_main a, hos_image b      
    WHERE       
      a.hos_id=b.hos_id       
    GROUP BY  
      a.hos_id   
    ORDER BY       
      b.hos_img_upload_date DESC,a.hos_id;
xnchan iT邦新手 5 級 ‧ 2013-04-30 18:54:07 檢舉

恩恩,我想明白了

4
xnchan
iT邦新手 5 級 ‧ 2013-04-30 10:59:35

不是按時間排列嗎?為什麼搞這麼複雜,你們看這樣行不行:

&lt;pre class="c" name="code">
SELECT     
  a.hos_name, b.hos_img_url    
FROM     
  hos_main a, hos_image b    
WHERE     
  a.hos_id=b.hos_id     
ORDER BY     
  UNIX_TIMESTAMP(b.hos_img_upload_date) DESC,a.hos_id    
LIMIT    
  1;    

把時間換成Unix 時間戳就可以排序了

看更多先前的回應...收起先前的回應...

不用換成Unix 時間戳也可以排序.
以下是使用敝人掰出來的範例,執行你上面的SQL Command的結果.

&lt;pre class="c" name="code">
SELECT     
  a.hos_name, b.hos_img_url    
FROM     
  hos_main a, hos_image b    
WHERE     
  a.hos_id=b.hos_id     
ORDER BY     
  UNIX_TIMESTAMP(b.hos_img_upload_date) DESC,a.hos_id    
LIMIT    
  1;    
+-----------------------+------------------------------------+
| hos_name              | hos_img_url                        |
+-----------------------+------------------------------------+
| 我是玄字一號房        | D:\img\玄字一號房\dark002.jpg      |
+-----------------------+------------------------------------+
&lt;pre class="c" name="code">
以下是換成Unix 時間戳的.
SELECT     
  a.hos_name, b.hos_img_url    
FROM     
  hos_main a, hos_image b    
WHERE     
  a.hos_id=b.hos_id     
ORDER BY     
  b.hos_img_upload_date DESC,a.hos_id
LIMIT 1;
+-----------------------+------------------------------------+
| hos_name              | hos_img_url                        |
+-----------------------+------------------------------------+
| 我是玄字一號房        | D:\img\玄字一號房\dark002.jpg      |
+-----------------------+------------------------------------+

上面說明弄錯了,是不換成Unix 時間戳的.

外獅佬 iT邦大師 1 級 ‧ 2013-04-30 11:56:50 檢舉

轉成字串,還是可以排序的....開心

ted99tw iT邦高手 1 級 ‧ 2013-04-30 13:02:15 檢舉

wiselou提到:
排序

夜市的烤肉串好像也可以...偷笑

先別管烤肉串了,把D槽交出來,不管是順排,逆排,根據演出者排,
更新時間排,依照種類分組排....都可以的啦..偷笑

xnchan提到:
不是按時間排列嗎?為什麼搞這麼複雜

因為你沒有考慮到 hos_main 超過一筆的情形
而使用 LIMIT 1
落寞

xnchan iT邦新手 5 級 ‧ 2013-04-30 14:08:28 檢舉

Orz平時因為要進行時間運算,都習慣了使用過程中的Unix 時間戳或DATE格式排序

我要發表回答

立即登入回答