joed 发表于 2007-1-5 21:19

求教一个数据库的问题.

$frage$

各位朋友, 你好.

小弟最近做一个有关Access数据库的作业时碰到一个计算和同个组件汇总的问题.具体如下:

A 产品 由 2个B1, 2个B2 和 2个A2构成

B1由3个C11 和 3个C12 组成
A2由3个B1 和 3个C12 组成

老师的要求是:
系统能够自动计算出: A 由2个B1, 8个B2 , 2个A2, 24个C11, 30个C12.

我自己设计的程序是分层计算.但相同的产品不会汇总:

第一层: 2个B1, 2个B2 和 2个A2
第二层: 在B1下面是6个C11 和 6个C12; A2下面是: 6个B1 和6个C12
第三层: 在B1 下面是18个C11, 和18个C12.

怎么样才能让我的程序汇总出A 是由2个B1, 8个B2 , 2个A2, 24个C11, 30个C12 构成的呢? 或者根本就不需要分成计算??

eisenstange 发表于 2007-1-6 11:38

如果是我,只能用SQL的子查询实现,Excel的实际应用我不太会。

看看有没有其他人能帮上忙,另外能否透露一下课名,这样大致有个方向。

joed 发表于 2007-1-7 01:04

:) 谢谢楼主的回帖! 我的课名是 Access 数据库的应用. 这里没有涉及到Excel. 请问楼主的"用SQL的子查询实现"能否具体点? 谢谢

eisenstange 发表于 2007-1-7 01:30

比如 select colum1 from table1 where colum2 in (select colum2 from table2 where colum3 = ‘xxx’);

joed 发表于 2007-1-7 13:45

谢谢答复. 也许是我没有真的明白你的意思. 但是我觉得版主的主意好像很难实现.
因为我的产品构成表分10层, 而且有可能同一个构成部件不只在2层出现,有可能3层,4层甚至9层都有. 每层具有N多个不同或者相同的部件产品. 根据排列组合的道理 这里的重复的部件产品已经接近无穷多. 如果用select语句一个个写出有可能重复的情况, 好像已经接近不可能了.
我的愚蠢的原Select代码如下,希望各位好友能指点, 哪怕是批评, 建议也好. 谢谢

SELECT costitemQry.productname, costitemQry.productmenge, costitemQry.description, IIf(costitemQry! Is Null,Null,1) AS 1, costitemQry., costitemQry., * AS sum1, costitemQry., IIf(costitemQry! Is Null,Null,2) AS 2, costitemQry., costitemQry., * AS sum2, costitemQry., IIf(costitemQry! Is Null,Null,3) AS 3, costitemQry., costitemQry., * AS sum3, costitemQry., IIf(costitemQry! Is Null,Null,4) AS 4, costitemQry., costitemQry., * AS sum4, costitemQry., IIf(costitemQry! Is Null,Null,5) AS 5, costitemQry., costitemQry., * AS sum5, costitemQry., IIf(costitemQry! Is Null,Null,6) AS 6, costitemQry., costitemQry., * AS sum6, costitemQry., IIf(costitemQry! Is Null,Null,7) AS 7, costitemQry., costitemQry., * AS sum7, costitemQry., IIf(costitemQry! Is Null,Null,8) AS 8, costitemQry., costitemQry., * AS sum8, costitemQry., IIf(costitemQry! Is Null,Null,9) AS 9, costitemQry., costitemQry., * AS sum9, costitemQry., IIf(costitemQry! Is Null,Null,10) AS 10, costitemQry., costitemQry., * AS sum10, costitemQry.
FROM costitemQry
ORDER BY costitemQry.productname, costitemQry., costitemQry., costitemQry., costitemQry., costitemQry., costitemQry., costitemQry., costitemQry., costitemQry., costitemQry.;

$考虑$

eisenstange 发表于 2007-1-7 14:15

你说的十层是指10个表么?

joed 发表于 2007-1-7 14:44

:) 10层是指有层次关系的产品构成. 比如如上面的Structure图: A产品由B1, B2 和 A2构成, 其中的B1, B2 和 A2就是第一层. B1下面的C11,C12就是第二层.
所有的产品基本上只放在一个表里面. 通过查询来实现它的功能.

我的Email: joed968@yahoo.com
05111325379
谢谢了

eisenstange 发表于 2007-1-7 20:21

能否把表结构放上来瞧瞧? 不过偶不是学Info的,说不定其他学Info的学生不需要也能作出来,就当是把你顶了。

joed 发表于 2007-1-8 01:03

:) 很乐意把我做的丑东东传上来,但是好像回帖时是传不少附件的呢.

cn1h 发表于 2007-1-8 15:22

我试着做了一下,并在MySQL上测试,可以得出结果,但是有两个小问题:

1。楼主提供的答案:“2个B1, 8个B2”是不是弄反了?应该是2个B2, 8个B1吧。
2。题目有没有给定条件,说明A类只包括A1,A2两种,B类只包括B1,B2两种,C类也只包括两种,依此类推一直到第10层?如果没有提供这样的条件,这道题将必须通过编程实现,也就是说要不停的做深度探测,比如如下情况理路上都是可以发生的:A1下有A2,A2下有A3。。。An下才有一个B1;这样是无法手动通过SQL实现查询的。

我是假设题目给定条件,每个字幕只有两种类型,也就是说如楼主例子中的情况,只有X1和X2。

建表结构:

A表:
+------+------+
| name | link |
+------+------+
| A1   | B1   |
| A1   | B1   |
| A1   | B2   |
| A1   | B2   |
| A1   | A2   |
| A1   | A2   |
| A2   | B1   |
| A2   | B1   |
| A2   | B1   |
| A2   | C12|
| A2   | C12|
| A2   | C12|
|      |      |
+------+------+

B表:

+------+------+
| name | link |
+------+------+
| B1   | C11|
| B1   | C11|
| B1   | C11|
| B1   | C12|
| B1   | C12|
| B1   | C12|
+------+------+


查询A只需直接查询A表


查询A2:

SELECT * FROM A WHERE name="A1" AND link="A2";




查询B需要直接查询A表,以及A-A的链接


查询B1:

SELECT * FROM A WHERE name="A1" AND link="B1"
union all
SELECT A2.name, A2.link FROM A AS A1 INNER JOIN A AS A2 ON A1.link=A2.name WHERE A1.name="A1" AND A2.link="B1";

查询B2:

SELECT * FROM A WHERE name="A1" AND link="B2"
union all
SELECT A2.name, A2.link FROM A AS A1 INNER JOIN A AS A2 ON A1.link=A2.name WHERE A1.name="A1" AND A2.link="B2";




查询C需要直接查询A表,以及A-A,A-B表的链接,以及A-A-B,A-B-B,A-A-B-B


查询C11:

SELECT * FROM A WHERE name="A1" AND link="C11"
union all
SELECT A2.name, A2.link FROM A AS A1 INNER JOIN A AS A2 ON A1.link=A2.name WHERE A1.name="A1" AND A2.link="C11"
union all
SELECT A.name, B.link FROM A INNER JOIN B ON A.link=B.name WHERE A.name="A1" AND B.link="C11"
union all
SELECT A1.name, B.link FROM A AS A1 INNER JOIN A AS A2 ON A1.link=A2.name INNER JOIN B ON A2.link=B.name WHERE A1.name="A1" AND B.link="C11"
union all
SELECT A.name, B2.link FROM A INNER JOIN B AS B1 ON A.link=B1.name INNER JOIN B AS B2 ON B1.link=B2.name WHERE A.name="A1" AND B2.link="C11"
union all
SELECT A1.name, B2.link FROM A AS A1 INNER JOIN A AS A2 ON A1.link=A2.name INNER JOIN B AS B1 ON A2.link=B1.name INNER JOIN B AS B2 ON B1.link=B2.name WHERE A1.name="A1" AND B2.link="C11";

查询C12:

SELECT * FROM A WHERE name="A1" AND link="C12"
union all
SELECT A2.name, A2.link FROM A AS A1 INNER JOIN A AS A2 ON A1.link=A2.name WHERE A1.name="A1" AND A2.link="C12"
union all
SELECT A.name, B.link FROM A INNER JOIN B ON A.link=B.name WHERE A.name="A1" AND B.link="C12"
union all
SELECT A1.name, B.link FROM A AS A1 INNER JOIN A AS A2 ON A1.link=A2.name INNER JOIN B ON A2.link=B.name WHERE A1.name="A1" AND B.link="C12"
union all
SELECT A.name, B2.link FROM A INNER JOIN B AS B1 ON A.link=B1.name INNER JOIN B AS B2 ON B1.link=B2.name WHERE A.name="A1" AND B2.link="C12"
union all
SELECT A1.name, B2.link FROM A AS A1 INNER JOIN A AS A2 ON A1.link=A2.name INNER JOIN B AS B1 ON A2.link=B1.name INNER JOIN B AS B2 ON B1.link=B2.name WHERE A1.name="A1" AND B2.link="C12";

cn1h 发表于 2007-1-8 15:38

探测深度可以用递归实现,例如

函数(节点){
if (节点.子节点都不属于同一个表格)
   exit;
else{
   数据库操作或者记录节点信息;
   函数(节点.子节点);
}
}

joed 发表于 2007-1-8 23:16

$送花$ 非常感谢cn1h的精彩答复! 你所指出的8个B1 和2个B2完全正确! 我后来也发现了这个问题,但是已经修改不了了.
在你设定的前提条件下,你的答复也很正确.非常感谢你的热心支持!

但是就像我在上面曾指出的: "产品构成表分10层, 而且有可能同一个构成部件不只在2层出现,有可能3层,4层甚至9层都有. 每层具有N多个不同或者相同的部件产品. 根据排列组合的道理 这里的重复的部件产品已经接近无穷多. 如果用select语句一个个写出有可能重复的情况, 好像已经接近不可能了."
而且,这个数据库是模拟厂家产品构成,组件计算的.实际的产品名称我们不可能都知道.即使都知道,以后的工厂生产过程中也可能增加别的零部件,那么我们的数据库又存在漏洞了.

所以小弟个人觉得我们不能定义寻找常量,只能寻找变量. 但是关于如何在数据库中寻找相同的变量并进行求和,我就只能请教各位高手了.

这段时间小弟都在日夜寻找这道题的答案.如果找到了.小弟一点公开.

再次谢谢cn1h大侠的指点!$握手$

cn1h 发表于 2007-1-9 11:03

呵呵,我也是菜鸟,和你一起思考,我也能学到东西。
关于这个题目,我还是有些看不太懂。最好能给出数据库表的结构,这个厂商应该告诉的吧。
另外推荐你一个论坛,www.csdn.net那里是我知道的国内IT最专业的论坛,上面有很多牛人,不像我们学生,人家很多都是正在前线拼杀的专业人士。你可以去数据库板块问问。

joed 发表于 2007-1-9 12:30

如果各位朋友需要我的数据库,请把你的Email给我. 我真的不知道怎么样把我做的东东传到论坛上.:)

eisenstange 发表于 2007-1-9 20:52

原帖由 joed 于 2007-1-9 11:30 发表
如果各位朋友需要我的数据库,请把你的Email给我. 我真的不知道怎么样把我做的东东传到论坛上.:)


其实如果是Access的话,你可以只把数据结构导出来,这样再压缩成rar或者Zip文件,理论上应该就可以上传了。

普通用户的上传限制好象是512k,我想如果只有表结构的话,应该没什么问题

祝你好运

$支持$ $支持$

joed 发表于 2007-1-9 22:08

请问版主,我看不到哪里有上传的字样啊?

eisenstange 发表于 2007-1-10 13:32

if you have enough right, then you can see the button on the bottle of the reply window

joed 发表于 2007-1-10 17:08

$郁闷$sorry, i don't have this right!

joed 发表于 2007-1-10 17:11

i think i can find the Solution and i will make it public as soon as possible$辛苦$ $辛苦$

eisenstange 发表于 2007-1-10 19:47

if you want, you can send the Data via email to me, and i post it then for you

:) :)

joed 发表于 2007-1-17 12:06

hi.
这道题终于有个眉目了:
在窗体上设立4个按键:
Gesamt_Auflistung, Stufen_Auflistung, Übersichts_Auflistung, Neuanlage tblZielTest

然后输入如下代码就行了:

Option Compare Database
Option Explicit
Dim bGefunden As Boolean
Dim bEnde As Boolean
Dim RettSchluessel(99)
Dim RettOberElement(99) As String
Dim RettMultiplikator(99) As Integer

Dim iStufe As Integer
Dim i As Integer

Dim stDocName As String

Dim OrigRst As DAO.Recordset
Dim ZielRst As DAO.Recordset

Private Sub Gesamt_Auflistung_Click()
      
    Bearb_Ziel
    stDocName = "rptZiel_Gesamt"
    DoCmd.OpenReport stDocName, acViewPreview

End Sub

Private Sub Bearb_Ziel()
    bGefunden = False
    bEnde = False
      
    Set OrigRst = CurrentDb.OpenRecordset("tblOriginal")
    Set ZielRst = CurrentDb.OpenRecordset("tblZiel")
               
    ' Loesche Zieltabelle "besonders quick and dirty"
    Do Until ZielRst.EOF
      ZielRst.Delete
      ZielRst.MoveNext
    Loop
   
    iStufe = 0
    RettMultiplikator(iStufe) = 1
   
    ' Lesen o-Datei mit Formularkey
   
    OrigRst.Index = "OberElement"
   
    OrigRst.Seek "=", Me.OberElement
   
    If OrigRst.NoMatch Then
      bEnde = True
    Else
      bGefunden = True
    End If
   
    Do Until bEnde
      If bGefunden Then
            ' Schreiben Zieltabelle
            ZielRst.AddNew
            ZielRst!UnterElement = OrigRst!UnterElement
            ZielRst!OrigAnzahl = OrigRst!Anzahl
            If iStufe = 0 Then
                ZielRst!Anzahl = OrigRst!Anzahl
            Else
                ZielRst!Anzahl = OrigRst!Anzahl
                'Multiplikation der Mengen mit den Vorstufen
                For i = iStufe To 1 Step -1
                   ZielRst!Anzahl = ZielRst!Anzahl * RettMultiplikator(iStufe - i)
                Next
            End If
            ZielRst!Stufe = iStufe
            
            ZielRst.Update
            
            RettSchluessel(iStufe) = OrigRst.Bookmark
            RettOberElement(iStufe) = OrigRst!OberElement
            RettMultiplikator(iStufe) = OrigRst!Anzahl
      End If
      
      ' Lesen Orig-Datei mit UE-Schluessel
      
      OrigRst.Seek "=", OrigRst!UnterElement
      
      If OrigRst.NoMatch Then
            AltePosUndNaechsten
      Else
            bGefunden = True
            iStufe = iStufe + 1
      End If
                     
    Loop
      
OrigRst.Close
ZielRst.Close

End Sub

Private Sub AltePosUndNaechsten()
    bEnde = False
    bGefunden = False
   
    Do Until bEnde = True Or bGefunden = True
   
      OrigRst.Bookmark = RettSchluessel(iStufe)
      OrigRst.MoveNext
      If Not OrigRst.EOF Then
            If OrigRst!OberElement = RettOberElement(iStufe) Then
                bGefunden = True
            Else
                If iStufe > 0 Then
                  iStufe = iStufe - 1
                Else
                   bEnde = True
                End If
            End If
      Else
            If iStufe > 0 Then
                iStufe = iStufe - 1
            Else
                bEnde = True
            End If
      End If
    Loop
   
End Sub

Private Sub Neuanlage_Click()
   
   ' Neuanlage tblZielTest
    Dim conn As ADODB.Connection
    Dim Info As Integer
   
    Set conn = CurrentProject.Connection
      ' Pruefung des Zustandes eines Datenbankobjektes
    '       0 = nicht geoeffnet oder nicht vorhanden
    '       1 = geoeffnet
    '       2 = geaendert, aber nicht gespeichertacSysCmdGetObjectState
    '       4 = Neu
    Info = SysCmd(acSysCmdGetObjectState, acTable, "tblZielTest")
   
    'Select Case Info
    'Case Is = 0
      ' Datei nicht vorhanden
    '    conn.Execute "DROP TABLE tblZielTest"
    'Case Is = 1
    '    conn.Execute "DROP TABLE tblZielTest"
    'Case Else
    '    MsgBox "Die Tabelle tblZielTest kann nicht geloescht werden"
    'End Select
   
    On Error GoTo Fehler
    conn.Execute "DROP TABLE tblZielTest"
   
    conn.Execute "CREATE TABLE tblZielTest " _
            & "(Autowert Counter, " _
            & "Unterelement char(10), " _
            & "Anzahl Integer, " _
            & "OrigAnzahl integer)"
   
    Set conn = Nothing
   
    GoTo FehlerEnde
   
Fehler:
    Select Case Err.Number
    Case Is = -2147217865
      MsgBox "Datei war nicht vorhanden"
      Resume Next
    Case Else
      Resume Next
    End Select
   
FehlerEnde:
   
End Sub

Private Sub Stufen_Auflistung_Click()
   
    Bearb_Ziel
    stDocName = "rptZiel_Stufe"
    DoCmd.OpenReport stDocName, acViewPreview

End Sub

Private Sub Uebersichts_Auflistung_Click()
   
    Bearb_Ziel
    stDocName = "rptZiel_uebersicht"
    DoCmd.OpenReport stDocName, acViewPreview
   
End Sub
$ok$
页: [1]
查看完整版本: 求教一个数据库的问题.