iT邦幫忙

1

PHP+SQLSRV,樹狀一對多,小找大,搜尋方式

  • 分享至 

  • xImage

公司產品資料類似這樣
https://ithelp.ithome.com.tw/upload/images/20200617/20127967TsKjcmcYd4.png

我資料庫規劃這樣 (為了能大找小,小找大)

https://ithelp.ithome.com.tw/upload/images/20200617/20127967KRdJRUzBh8.png
補充:
大組件可能會共用中組件.小組件,零件...等

老闆說會跑太久,他自己規劃這樣
利用大組件找到中組件,再用中組件一開頭編號分類找到其餘底下小組件或零件
https://ithelp.ithome.com.tw/upload/images/20200617/20127967w2IpMcoGmM.png

如下圖中組件都是6開頭,則到6開頭資料表找尋更下層
https://ithelp.ithome.com.tw/upload/images/20200617/201279671bSvic1MaY.png
資料量大概大組件共三萬個

公司需求:查詢任何代號可以找到其上下階層關係

想請問 1.老闆方式若要小找大,不是會花更久時間嗎?或是有其他規畫格式,或是有其他搜尋方式
2.最後需樹狀呈現在網頁上,是用4個迴圈寫,感覺會跑很慢(因為目前只用部分資料測試),有其他更好寫法嗎

謝謝

看更多先前的討論...收起先前的討論...
這是個好問題, 追蹤看高手解答
雖然可能對答案沒什麼影響
不過你舉的範例資料會有點造成誤導, 就是
大組件不可以/不會共用(使用同一個)中組件
中組件不可以/不會共用(使用同一個)小組件
而事實上你老闆的範例資料裡
是「會的」(一般實務情形也是如此)
s34631327 iT邦新手 5 級 ‧ 2020-06-17 09:44:01 檢舉
感謝提醒,我有補充上去
WQ iT邦新手 2 級 ‧ 2020-06-17 10:23:39 檢舉
這個CASE接了,再發包給海綿寶寶客制!!
firecold iT邦新手 1 級 ‧ 2020-06-17 16:35:00 檢舉
用Nested做吧
可參考baum
共用的方式用關聯做
額外開大中小主鍵model table
做起來應該跟星空大建議的一樣
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
1
froce
iT邦大師 1 級 ‧ 2020-06-17 16:01:32
最佳解答

這...不是用外鍵就能做了嗎?
都是一對多。

大類:

id
名稱:

中類:

id
關聯的大類id
名稱:

小類:

id
關聯的中類id
名稱:

要在sql用的話要用遞迴,但是要在django orm的話非常容易...
不過跟php沒關就是。

1

正常是要用你老闆的觀念。也就是關聯應用的方式處理。
建議採用關聯的方式。

不過的確你的說明並不是很清楚。所以也沒辦法了解你實際真正的需求為何。

就我個人而言。會將資料跟分類(組件)拆開組合
這樣分類好做樹狀處理。

s34631327 iT邦新手 5 級 ‧ 2020-06-17 10:00:18 檢舉

感謝前輩回答!
請問有哪裡說不清楚呢

因為現在資料表規劃是依"大找小"規劃
這樣"小找大"(從零件或小組件能找到其相關上下關係)
會出現問題或跑很慢嗎

其實如果關聯有做好。都可以往上往下拿資料。
正常來講,小找大還單純多了。

一般來說,我會多增加一個組件分類的表來做樹狀處理。
而主資料表只要關聯好對應的組件id就好了。

1
WQ
iT邦新手 2 級 ‧ 2020-06-17 10:15:27

階層TABLE寫法
假設生產料件是用A做成B,用B做成C,用C做成D....依此推
只要建一個TABLE就可以了
生產料件,生產量,使用料件,使用量....其它欄位依自已需求建立
由上述欄位得到此表格(以,區隔--請想像它是表格...)
A,1,B,2 -->生產A一個要用B二個原料或半製品
B,1,C,2 -->生產B一個要用C二個原料或半製品
C,1,D,4 ........
以上為一對一生產BOM表範例
一對多則只是程式上寫法不同,資料表也可用同一個去記錄。
A,1,B1,2
A,1,B2,1
A,1,B3,4.....
如此使用,即可解決您的問題,至於要展到幾階就看貴公司生產BOM表的階數來看了....
當你查A時,系統會帶出A要用B1,B2,B3等原料半製品,再去展出B1要用什麼,只是把B1放在生產料件去看,就會查得您要的資料。

補充一下:至於要順推或反推只是查詢欄位條件設定

1
一級屠豬士
iT邦大師 1 級 ‧ 2020-06-17 10:45:55

遞迴查詢.這個參考資料很多.看你放的標籤ms sql, 應該是用SQL Server, 他有遞迴查詢的功能,
可以試試看. 這是主流. 不懂再來問.
另外
SQL Server 2008 版以後有 hierarchyid data type.
https://docs.microsoft.com/zh-tw/sql/relational-databases/tables/tutorial-using-the-hierarchyid-data-type?view=sql-server-ver15

有一位很久沒出現的Rico , 有寫一篇
https://dotblogs.com.tw/ricochen/2018/06/02/145338

關於這種方式,我在之前有寫一些,有興趣可以參考.
https://ithelp.ithome.com.tw/articles/10227730

https://ithelp.ithome.com.tw/articles/10227989

https://ithelp.ithome.com.tw/articles/10228784

MySQL的話,要8版以後才有遞迴查詢功能. 之前的版本若是要做遞迴查詢,要自己加工.
https://ithelp.ithome.com.tw/questions/10195812

1
ckp6250
iT邦好手 1 級 ‧ 2020-06-17 16:47:27

這不就是一般【功能表】的樣式嗎?
殺豬大都已經提出線索啦。

我覺得資料庫規劃不需要用什麼【大組件、中組件、小組件、零件】這樣會受到層次限制,關鍵主鍵應該只有二個欄位,【我本身的id,我的爸爸的id】,不管大找小或小找大,通通適用。

當找到我的id時,同時看看我的爸爸的id是什麼,然後再用爸爸的id,去找他的爸爸id,一直找到沒有爸爸為止。

0
rogeryao
iT邦超人 8 級 ‧ 2020-06-18 16:28:10
CREATE TABLE [dbo].[depX] (
[Id] varchar(20) NULL ,
[ParentId] varchar(20) NULL 
);
CREATE TABLE [dbo].[product_dtl] (
[productid] varchar(50) NOT NULL ,
[productname] varchar(50) NULL ,
[productspec] varchar(50) NULL 
);
SELECT
      CONVERT(varchar, DENSE_RANK() OVER (ORDER BY A.Id))+'A' AS level_01,
      isnull(A.Id,'*') + isnull(' : ' + dtl_big.productname,'')  + isnull(' : ' + dtl_big.productspec,'') as Id_01,

      CONVERT(varchar, DENSE_RANK() OVER (ORDER BY A.Id))+'A' + '.' +
      CONVERT(varchar, DENSE_RANK() OVER (PARTITION BY A.Id ORDER BY A.Id, B.Id))+'B' AS level_02,
      isnull(B.Id,'*') + isnull(' : ' + dtl_medi.productname,'')  + isnull(' : ' + dtl_medi.productspec,'') as Id_02,

      CONVERT(varchar, DENSE_RANK() OVER (ORDER BY A.Id))+'A' + '.' +
      CONVERT(varchar, DENSE_RANK() OVER (PARTITION BY A.Id ORDER BY A.Id, B.Id))+'B' + '.' +
      CONVERT(varchar, DENSE_RANK() OVER (PARTITION BY A.Id, B.Id ORDER BY A.Id, B.Id, C.Id))+'C' AS level_03,
      isnull(C.Id,'*') + isnull(' : ' + dtl_small.productname,'')  + isnull(' : ' + dtl_small.productspec,'') as Id_03

FROM depX AS A
LEFT JOIN depX AS B
  ON B.ParentId = A.Id
LEFT JOIN depX AS C
  ON C.ParentId = B.Id

LEFT JOIN product_dtl AS dtl_big
  ON dtl_big.productId = A.Id
LEFT JOIN product_dtl AS dtl_medi
  ON dtl_medi.productId = B.Id
LEFT JOIN product_dtl AS dtl_small
  ON dtl_small.productId = C.Id

WHERE 1 = 1
-- 最上層品號 id 的 ParentId =''
AND A.ParentId = ''
ORDER BY A.Id, B.Id, C.Id

Demo

s34631327 iT邦新手 5 級 ‧ 2020-06-18 16:30:05 檢舉

感謝,我研究下

我要發表回答

立即登入回答