设为首页收藏本站Access中国

Office中国论坛/Access中国论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

12下一页
返回列表 发新帖
查看: 7184|回复: 13
打印 上一主题 下一主题

[模块/函数] “排队不长,只是很粗”——浅谈化宽为长

[复制链接]
跳转到指定楼层
1#
发表于 2017-3-11 18:51:57 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

记得初中时住校吃饭堂,那时候每周伙食费是20元。早上1元,午餐晚餐各1.5元(周末则回家)。

早餐一般是一碗很稀的粥,上面漂浮着一块或者两块油汪汪的肥肉,外加一个包子。星期三则是猪骨头汤米粉,——当然是没有包子了,——所以,早操一结束,大家就集体逃亡一般奔向饭堂。最开始冲过去的在每个窗口前排成两列,排到十几个之后,后面的大都是女生。其它男同学则会绕到侧面,伺机斜插进去。

曾经有个走读的同学问我,住校时排队很长吗?我认真地想了想,“排队不长,只是很粗”。她笑了,“你很幽默。”然后我也笑了,虽然我并不是一个幽默的人。直到后来学生会组织了一些学生干部专门去维持秩序,才开始“化宽为长”。


正如太宽的队伍常常有不遵守秩序的嫌疑,太宽的数据表也常常有不遵守第二范式的嫌疑。而违反它,在数据库中往往会引发很多问题,表维护不方便,难以统计分析,查询不好处理等等……所以“化宽为长”就变得很重要了。

化宽为长的前提是要求“宽”的那部分拥有共同的属性,就像宽的那部分队伍一样(都是男同学,都在队伍侧面),例如,都是数值型,都在最右边的字段等等。如果没有这些,当然谈不上化宽为长了。先看看效果吧:

代码如下,具体见示例文件。喜欢的话,就回个帖吧。

  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. '查找字段分割点的位置
  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. '在分割点之前,直接连接字符串
  20.         If i <= lngEnd Then
  21.             strSQL = strSQL & rst.Fields(i).Name & ","
  22.         Else
  23. '在分割点之后,写入字典,用于确定变量名和变量值。
  24.             dic.Add i, rst.Fields(i).Name
  25.             
  26.         End If
  27.     Next
  28. '关闭记录集
  29.     rst.Close
  30.    
  31.     '准备语句
  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
复制代码


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

评分

参与人数 1经验 +6 收起 理由
zpy2 + 6 (V币)优秀原创教程、管理建议(1-5分)

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享分享 分享淘帖 订阅订阅

点击这里给我发消息

2#
发表于 2017-3-11 18:58:16 | 只看该作者
你总是离不开吃

点击这里给我发消息

3#
发表于 2017-3-12 07:34:12 | 只看该作者
这是传说中的二维转一维吗,赞一个

点击这里给我发消息

4#
发表于 2017-3-12 10:02:54 | 只看该作者
本帖最后由 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.   '查找字段分割点的位置
  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.     '在分割点之前,直接连接字符串
  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.       '在分割点之前,直接连接字符串
  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("提成等级表", "百分点")
  57. End Sub



复制代码
用临时表作了下,好像代码多了点。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
5#
发表于 2017-3-12 10:47:14 | 只看该作者
肉一,你这是降维打击么?
6#
 楼主| 发表于 2017-3-12 22:41:57 | 只看该作者
zpy2 发表于 2017-3-12 10:02
用临时表作了下,好像代码多了点。

创建临时表有2个问题,
1、处理字段类型。
这里是double,换了别的,可能会是single或者long等等。考虑到通用性,所以我没有使用这个方式。
2、插入数据的效率问题。
创建临时表一般需要嵌套循环插入,当数据量较大时可能会有些许延时。至于修改已存在的查询语句,会否存在这个问题,暂时未测试。不过,窃以为执行选择查询会比追加查询快一些。
7#
 楼主| 发表于 2017-3-12 22:43:53 | 只看该作者
红尘如烟 发表于 2017-3-12 10:47
肉一,你这是降维打击么?

当时看到那个附件,想死的心都有了:
http://www.office-cn.net/thread-122659-1-1.html
8#
发表于 2017-3-13 12:15:39 | 只看该作者
我以为是腿粗呢,roych 老师为什么早餐粥上漂肥肉呀?啥饭?
9#
发表于 2017-3-13 15:01:10 | 只看该作者
生活真美好,一天20元,早餐还有肉吃。
我上学时一个月才15元的生活费、
10#
发表于 2017-3-13 15:03:09 | 只看该作者
excel里有个逆透视
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|站长邮箱|小黑屋|手机版|Office中国/Access中国 ( 粤ICP备10043721号-1 )  

GMT+8, 2024-11-25 04:34 , Processed in 0.104437 second(s), 39 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表