Office中國(guó)論壇/Access中國(guó)論壇

標(biāo)題: “排隊(duì)不長(zhǎng),只是很粗”——淺談化寬為長(zhǎng) [打印本頁(yè)]

作者: roych    時(shí)間: 2017-3-11 18:51
標(biāo)題: “排隊(duì)不長(zhǎng),只是很粗”——淺談化寬為長(zhǎng)

記得初中時(shí)住校吃飯?zhí),那時(shí)候每周伙食費(fèi)是20元。早上1元,午餐晚餐各1.5元(周末則回家)。

早餐一般是一碗很稀的粥,上面漂浮著一塊或者兩塊油汪汪的肥肉,外加一個(gè)包子。星期三則是豬骨頭湯米粉,——當(dāng)然是沒有包子了,——所以,早操一結(jié)束,大家就集體逃亡一般奔向飯?zhí)。最開始沖過(guò)去的在每個(gè)窗口前排成兩列,排到十幾個(gè)之后,后面的大都是女生。其它男同學(xué)則會(huì)繞到側(cè)面,伺機(jī)斜插進(jìn)去。

曾經(jīng)有個(gè)走讀的同學(xué)問我,住校時(shí)排隊(duì)很長(zhǎng)嗎?我認(rèn)真地想了想,“排隊(duì)不長(zhǎng),只是很粗”。她笑了,“你很幽默!比缓笪乙残α,雖然我并不是一個(gè)幽默的人。直到后來(lái)學(xué)生會(huì)組織了一些學(xué)生干部專門去維持秩序,才開始“化寬為長(zhǎng)”。


正如太寬的隊(duì)伍常常有不遵守秩序的嫌疑,太寬的數(shù)據(jù)表也常常有不遵守第二范式的嫌疑。而違反它,在數(shù)據(jù)庫(kù)中往往會(huì)引發(fā)很多問題,表維護(hù)不方便,難以統(tǒng)計(jì)分析,查詢不好處理等等……所以“化寬為長(zhǎng)”就變得很重要了。

化寬為長(zhǎng)的前提是要求“寬”的那部分擁有共同的屬性,就像寬的那部分隊(duì)伍一樣(都是男同學(xué),都在隊(duì)伍側(cè)面),例如,都是數(shù)值型,都在最右邊的字段等等。如果沒有這些,當(dāng)然談不上化寬為長(zhǎng)了。先看看效果吧:

[attach]60945[/attach]

代碼如下,具體見示例文件。喜歡的話,就回個(gè)帖吧。

  1. Function getSQL(ByVal strTableName As String, ByVal strEndFieldName As String) As String
  2.     Dim rst As New ADODB.Recordset
  3.     Dim i As Long
  4.     Dim lngPosition As Long
  5.     Dim strSQL As String, strSQL2 As String
  6.     Dim dic As New Dictionary
  7.     Dim lngEnd As Long
  8.    
  9.     rst.Open strTableName, CurrentProject.Connection, adOpenKeyset, adLockOptimistic
  10. '查找字段分割點(diǎn)的位置
  11.     For i = 0 To rst.Fields.Count - 1
  12.         If rst.Fields(i).Name = strEndFieldName Then
  13.             lngEnd = i
  14.             Exit For
  15.         End If
  16.     Next
  17. '切割字段
  18.     For i = 0 To rst.Fields.Count - 1
  19. '在分割點(diǎn)之前,直接連接字符串
  20.         If i <= lngEnd Then
  21.             strSQL = strSQL & rst.Fields(i).Name & ","
  22.         Else
  23. '在分割點(diǎn)之后,寫入字典,用于確定變量名和變量值。
  24.             dic.Add i, rst.Fields(i).Name
  25.             
  26.         End If
  27.     Next
  28. '關(guān)閉記錄集
  29.     rst.Close
  30.    
  31.     '準(zhǔn)備語(yǔ)句
  32.     For i = 0 To dic.Count - 1
  33.         strSQL2 = strSQL2 & "select " & strSQL & """" & _
  34.                 dic.Items(i) & """ as 變量名稱,[" & _
  35.                 dic.Items(i) & "] as 變量值 from " & strTableName & " union all "
  36.     Next
  37.    
  38.     getSQL = Left(strSQL2, Len(strSQL2) - 11)
  39.                
  40. End Function
復(fù)制代碼

[attach]60947[/attach]



作者: tmtony    時(shí)間: 2017-3-11 18:58
你總是離不開吃
作者: zpy2    時(shí)間: 2017-3-12 07:34
這是傳說(shuō)中的二維轉(zhuǎn)一維嗎,贊一個(gè)
作者: zpy2    時(shí)間: 2017-3-12 10:02
本帖最后由 zpy2 于 2017-3-12 10:05 編輯
  1. Option Compare Database
  2. Option Explicit

  3. Function getSQL2(ByVal strTableName As String, ByVal strEndFieldName As String) As String
  4.   On Error Resume Next
  5.   Dim rst As DAO.Recordset, rst2
  6.   Dim i As Long
  7.   Dim j As Long
  8.   Dim strSQL As String, strSQL2 As String
  9.   Dim lngEnd As Long
  10.   
  11.   Set rst = CurrentDb.OpenRecordset("select * from " & strTableName)
  12.   '查找字段分割點(diǎn)的位置
  13.   For i = 0 To rst.Fields.Count - 1
  14.     If rst.Fields(i).Name = strEndFieldName Then
  15.       lngEnd = i
  16.       Exit For
  17.     End If
  18.   Next
  19.   
  20.   '這里省去了 判斷 表否存在
  21.   strSQL = "DROP TABLE tempTable"
  22.   CurrentDb.Execute strSQL
  23.   strSQL = "CREATE TABLE tempTable ("
  24.   For i = 0 To rst.Fields.Count - 1
  25.     '在分割點(diǎn)之前,直接連接字符串
  26.     If i <= lngEnd Then
  27.       strSQL = strSQL & rst.Fields(i).Name & " TEXT,"
  28.     Else
  29.       Exit For
  30.     End If
  31.   Next
  32.   strSQL = strSQL & "變量值 DOUBLE)"
  33.   CurrentDb.Execute strSQL
  34.   Rem 這段比union方法看這不同
  35.   strSQL = "SELECT * FROM tempTable"
  36.   Set rst2 = CurrentDb.OpenRecordset(strSQL)
  37.   Do While Not rst.EOF
  38.    
  39.     For i = lngEnd + 1 To rst.Fields.Count - 1
  40.       '在分割點(diǎn)之前,直接連接字符串
  41.       rst2.AddNew
  42.       For j = 0 To lngEnd
  43.         rst2.Fields(j) = rst.Fields(j)
  44.       Next
  45.       rst2.Fields(lngEnd + 1) = rst.Fields(i)
  46.       rst2.Update
  47.       
  48.     Next i
  49.     rst.MoveNext
  50.   Loop
  51.   rst2.Close
  52.   rst.Close
  53. End Function

  54. Sub runOnce()
  55.   Dim x
  56.   x = getSQL2("提成等級(jí)表", "百分點(diǎn)")
  57. End Sub



復(fù)制代碼
用臨時(shí)表作了下,好像代碼多了點(diǎn)。

作者: 紅塵如煙    時(shí)間: 2017-3-12 10:47
肉一,你這是降維打擊么?
作者: roych    時(shí)間: 2017-3-12 22:41
zpy2 發(fā)表于 2017-3-12 10:02
用臨時(shí)表作了下,好像代碼多了點(diǎn)。

創(chuàng)建臨時(shí)表有2個(gè)問題,
1、處理字段類型。
這里是double,換了別的,可能會(huì)是single或者long等等。考慮到通用性,所以我沒有使用這個(gè)方式。
2、插入數(shù)據(jù)的效率問題。
創(chuàng)建臨時(shí)表一般需要嵌套循環(huán)插入,當(dāng)數(shù)據(jù)量較大時(shí)可能會(huì)有些許延時(shí)。至于修改已存在的查詢語(yǔ)句,會(huì)否存在這個(gè)問題,暫時(shí)未測(cè)試。不過(guò),竊以為執(zhí)行選擇查詢會(huì)比追加查詢快一些。
作者: roych    時(shí)間: 2017-3-12 22:43
紅塵如煙 發(fā)表于 2017-3-12 10:47
肉一,你這是降維打擊么?

當(dāng)時(shí)看到那個(gè)附件,想死的心都有了:
http://mzhfr.cn/thread-122659-1-1.html
作者: yanwei82123300    時(shí)間: 2017-3-13 12:15
我以為是腿粗呢,roych 老師為什么早餐粥上漂肥肉呀?啥飯?
作者: Henry D. Sy    時(shí)間: 2017-3-13 15:01
生活真美好,一天20元,早餐還有肉吃。
我上學(xué)時(shí)一個(gè)月才15元的生活費(fèi)、
作者: Henry D. Sy    時(shí)間: 2017-3-13 15:03
excel里有個(gè)逆透視
作者: roych    時(shí)間: 2017-3-14 17:17
yanwei82123300 發(fā)表于 2017-3-13 12:15
我以為是腿粗呢,roych 老師為什么早餐粥上漂肥肉呀?啥飯?

超級(jí)難吃好不好,看著就覺得油膩得很了,而且有可能是豬脖子肉
作者: roych    時(shí)間: 2017-3-14 17:30
Henry D. Sy 發(fā)表于 2017-3-13 15:01
生活真美好,一天20元,早餐還有肉吃。
我上學(xué)時(shí)一個(gè)月才15元的生活費(fèi)、

一個(gè)星期20元……一個(gè)月15,你是什么時(shí)候上學(xué)的?
作者: Henry D. Sy    時(shí)間: 2017-3-15 17:22
roych 發(fā)表于 2017-3-14 17:30
一個(gè)星期20元……一個(gè)月15,你是什么時(shí)候上學(xué)的?

79年
作者: 冚友    時(shí)間: 2018-11-2 11:18
學(xué)習(xí)了,謝謝大師!




歡迎光臨 Office中國(guó)論壇/Access中國(guó)論壇 (http://mzhfr.cn/) Powered by Discuz! X3.3