项目中经常会用到Excel上传到数据库中的功能或者读取一个Excel在GridView中显示出来的情况。

基本原理就是获取Excel的连接,读取Excel的数据到DataSet。 根据DataSet的结果来显示内容或者把DataSet的结果更新到数据库中。

      以下就贴出代码并加上简单的注释。

 

Imports System.Data
Imports System.Data.SqlClient '连接SQLSERVER数据库
Imports System.Data.OleDb     '连接Excel工作表

Partial Class Default_Excel
    Inherits System.Web.UI.Page

    Protected Sub btnImport_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnImport.Click
        Dim fup As FileUpload
        Dim strPath As String = ""
        Dim i As Integer = 0
        Dim dataTable As New DataTable

        '获取上传控件

        fup = Me.form1.FindControl("FileUpload1")
        strPath = fup.PostedFile.FileName

        If strPath = "" Then
            Response.Write(" <script> alert( '请先选择正确的Excel文件导入! ') </script> ")
            Response.End()
        End If

        '定义Excel连接字符串
        Dim sConnectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strPath & "; Extended Properties=Excel 8.0;"
        Try
            Dim oleDbConnection As OleDbConnection = New OleDbConnection(sConnectionString)
            oleDbConnection.Open()
            '获取excel表
            dataTable = oleDbConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, Nothing)

            '获取sheet名,其中(0)(1)...(N): 按名称排列的表单元素
            '固定是读取一个工作表

            Dim tableName As String = dataTable.Rows(0)(2).ToString().Trim()
            tableName = "[" & tableName.Replace(" ' ", " ") & "]"

    '以下SELECT 中的字段名要和Excel工作表中的一致

            Dim query As String = "SELECT 字段名1,字段名2, 字段名3,字段名4,字段名5 FROM " & tableName
            Dim dataset As DataSet = New DataSet()
            Dim oleAdapter As OleDbDataAdapter = New OleDbDataAdapter(query, sConnectionString)
            oleAdapter.Fill(dataset, "Rwb")

    '连接SQLSERVER数据库

            Dim sqlcon As New SqlConnection(SqlOpe.ConnStr)
            sqlcon.Open()
            '从excel文件获得数据后,插入记录到SQL Server的数据表
            Dim dataTable1 As DataTable = New DataTable()

            '以下字段名是数据库中 表中的字段名称
            Dim sqlDA1 As SqlClient.SqlDataAdapter = New SqlClient.SqlDataAdapter("SELECT YEARS, PERIOD, WERKS, MATNR, BISMT,VERSION , REQQTY  FROM ProdS_ForeCast WHERE 1<>1 ", sqlcon)
            Dim sqlCB1 As SqlClient.SqlCommandBuilder = New SqlClient.SqlCommandBuilder(sqlDA1)
            sqlDA1.Fill(dataTable1)

            Dim dataRow11 As DataRow
            For Each dataRow11 In dataset.Tables("Rwb").Rows
                'sql里数据dataRow1
                Dim dataRow1 As DataRow = dataTable1.NewRow()
                dataRow1("YEARS") = dataRow11("字段名1")
                dataRow1("PERIOD") = dataRow11("字段名2")
                dataRow1("WERKS") = dataRow11("字段名3")
                dataRow1("MATNR") = dataRow11("字段名4")
                dataRow1("BISMT") = dataRow11("字段名5")
                dataTable1.Rows.Add(dataRow1)
            Next
            Response.Write(" <script> alert( '一共导入 " & dataset.Tables("Rwb").Rows.Count.ToString() & " 条记录  ') </script> ")
            sqlDA1.Update(dataTable1)
            oleDbConnection.Close()
        Catch ex As Exception
            Console.WriteLine(ex.ToString())
        End Try
    End Sub

End Class

如果需要在GridView中显示将DataSet的结果绑定到GridView的DataSource就可以了

 

 

posted @ 2010-10-12 11:18 寒天飞雪 阅读(162) 评论(0) 编辑

 

众所周知,银行住房贷款的分期付款方式分为等额本息付款和等额本金方式付款两种方式。两种付款方式的月付款额各不相同,计算方式也不一样。网上分别 有着两种还款方式的计算公式。然而,对于这两个公式的来源却很少有解释,或者解释是粗略的或错误的。本人经过一段时间的思考,终于整明白了其中的原理,并 且运用高中数学理论推导出了这两个计算公式。本文将从原理上解释一下着两种还款方式的原理及计算公式的推导过程。

无论哪种还款方式,都有一个共同点,就是每月的还款额(也称月供)中包含两个部分:本金还款和利息还款:

月还款额=当月本金还款+当月利息 式1

其中本金还款是真正偿还贷款的。每月还款之后,贷款的剩余本金就相应减少:

当月剩余本金=上月剩余本金-当月本金还款

直到最后一个月,全部本金偿还完毕。

利息还款是用来偿还剩余本金在本月所产生的利息的。每月还款中必须将本月本金所产生的利息付清:

当月利息=上月剩余本金×月利率 式2

其中月利率=年利率÷12。据传工商银行等某些银行在进行本金等额还款的计算方法中,月利率用了一个挺孙子的算法,这里暂且不提。

由上面利息偿还公式中可见,月利息是与上月剩余本金成正比的,由于在贷款初期,剩余本金较多,所以可见,贷款初期每月的利息较多,月还款额中偿还利 息的份额较重。随着还款次数的增多,剩余本金将逐渐减少,月还款的利息也相应减少,直到最后一个月,本金全部还清,利息付最后一次,下个月将既无本金又无 利息,至此,全部贷款偿还完毕。

两种贷款的偿还原理就如上所述。上述两个公式是月还款的基本公式,其他公式都可由此导出。下面我们就基于这两个公式推导一下两种还款方式的具体计算公式。

1. 等额本金还款方式

等额本金还款方式比较简单。顾名思义,这种方式下,每次还款的本金还款数是一样的。因此:

当月本金还款=总贷款数÷还款次数

当月利息=上月剩余本金×月利率

=总贷款数×(1-(还款月数-1)÷还款次数)×月利率

当月月还款额=当月本金还款+当月利息

=总贷款数×(1÷还款次数+(1-(还款月数-1)÷还款次数)×月利率)

总利息=所有利息之和

=总贷款数×月利率×(还款次数-(1+2+3+。。。+还款次数-1)÷还款次数)

其中1+2+3+…+还款次数-1是一个等差数列,其和为(1+还款次数-1)×(还款次数-1)/2=还款次数×(还款次数-1)/2

所以,经整理后可以得出:

总利息=总贷款数×月利率×(还款次数+1)÷2

由于等额本金还款每个月的本金还款额是固定的,而每月的利息是递减的,因此,等额本金还款每个月的还款额是不一样的。开始还得多,而后逐月递减。

2. 等额本息还款方式

等额本息还款方式的公式推导比较复杂,不过也不必担心,只要具备高中数列知识就可以推导出来了。

等额本金还款,顾名思义就是每个月的还款额是固定的。由于还款利息是逐月减少的,因此反过来说,每月还款中的本金还款额是逐月增加的。

首先,我们先进行一番设定:

设:总贷款额=A

还款次数=B

还款月利率=C

月还款额=X

当月本金还款=Yn(n=还款月数)

先说第一个月,当月本金为全部贷款额=A,因此:

第一个月的利息=A×C

第一个月的本金还款额

Y1=X-第一个月的利息

=X-A×C

第一个月剩余本金=总贷款额-第一个月本金还款额

=A-(X-A×C)

=A×(1+C)-X

再说第二个月,当月利息还款额=上月剩余本金×月利率

第二个月的利息=(A×(1+C)-X)×C

第二个月的本金还款额

Y2=X-第二个月的利息

=X-(A×(1+C)-X)×C

第二个月剩余本金=第一个月剩余本金-第二个月本金还款额

=A×(1+C)-X-(X-(A×(1+C)-X)×C)

=A×(1+C)-X-X+(A×(1+C)-X)×C

=A×(1+C)×(1+C)-[X+(1+C)×X]

=A×(1+C)^2-[X+(1+C)×X]

(1+C)^2表示(1+C)的2次方

第三个月,

第三个月的利息=第二个月剩余本金×月利率

第三个月的利息=(A×(1+C)^2-[X+(1+C)×X])×C

第三个月的本金还款额

Y3=X-第三个月的利息

=X-(A×(1+C)^2-[X+(1+C)×X])×C

第三个月剩余本金=第二个月剩余本金-第三个月的本金还款额

=A×(1+C)^2-[X+(1+C)×X]

-(X-(A×(1+C)^2-[X+(1+C)×X])×C)

=A×(1+C)^2-[X+(1+C)×X]

-(X-(A×(1+C)^2×C+[X+(1+C)×X])×C)

=A×(1+C)^2×(1+C)

-(X+[X+(1+C)×X]×(1+C))

=A×(1+C)^3 -[X+(1+C)×X+(1+C)^2×X]

上式可以分成两个部分

第一部分:A×(1+C)^3。

第二部分:[X+(1+C)×X+(1+C)^2×X]

=X×[1+(1+C)+(1+C)^2]

通过对前三个月的剩余本金公式进行总结,我们可以看到其中的规律:

剩余本金中的第一部分=总贷款额×(1+月利率)的n次方,(其中n=还款月数)

剩余本金中的第二部分是一个等比数列,以(1+月利率)为比例系数,月还款额为常数系数,项数为还款月数n。

推广到任意月份:

第n月的剩余本金=A×(1+C)^n -X×Sn(Sn为(1+C)的等比数列的前n项和)

根据等比数列的前n项和公式:

1+Z+Z2+Z3+...+Zn-1=(1-Z^n)/(1-Z)

可以得出

X×Sn=X×(1-(1+C)^n)/(1-(1+C))

=X×((1+C)^n-1)/C

所以,第n月的剩余本金=A×(1+C)^n-X×((1+C)^n-1)/C

由于最后一个月本金将全部还完,所以当n等于还款次数时,剩余本金为零。

设n=B(还款次数)

剩余本金=A×(1+C)^B-X×((1+C)^B-1)/C=0

从而得出

月还款额

X=A×C×(1+C)^B÷((1+C)^B-1)

=  总贷款额×月利率×(1+月利率)^还款次数÷[(?000保 吕 剩还款次数-1]

将X值带回到第n月的剩余本金公式中

第n月的剩余本金=A×(1+C)^n-[A×C×(1+C)^B/((1+C)^B-1)]×((1+C)^n-1)/C

=A×[(1+C)^n-(1+C)^B×((1+C)^n-1)/((1+C)^B-1)]

=A×[(1+C)^B-(1+C)^n]/((1+C)^B-1)

第n月的利息=第n-1月的剩余本金×月利率

=A×C×[(1+C)^B-(1+C)^(n-1)]/((1+C)^B-1)

第n月的本金还款额=X-第n月的利息

=A×C×(1+C)^B/((1+C)^B-1)-A×C×[(1+C)^B-(1+C)^(n-1)]/((1+C)^B-1)

=A×C×(1+C)^(n-1)/((1+C)^B-1)

总还款额=X×B

=A×B×C×(1+C)^B÷((1+C)^B-1)

总利息=总还款额-总贷款额=X×B-A

=A×[(B×C-1)×(1+C)^B+1]/((1+C)^B-1)

等额本息还款,每个月的还款额是固定的。由于还款初期利息较大,因此初期的本金还款额很小。相对于等额本金方式,还款的总利息要多。

 

posted @ 2009-04-20 10:24 寒天飞雪 阅读(337) 评论(0) 编辑

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SAPFunctionsOCX;
using SAPLogonCtrl;
using SAPTableFactoryCtrl;

namespace SAPFunction
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

      
        private void BtnConn_Click(object sender, EventArgs e)
        {  
               //设置登录连接的类
                DataSet dset = new DataSet();
                SAPLogonCtrl.SAPLogonControlClass logon = new SAPLogonCtrl.SAPLogonControlClass();
                //连接参数设置
                logon.ApplicationServer = "172.18.95.173";
                logon.Client = "164";
                logon.Language = "ZH";
                logon.User = "CRMDEV69";
                logon.Password = "654321";
                logon.SystemNumber = 7;
               
                //实例化连接对象
                SAPLogonCtrl.Connection Conn;

                Conn = (SAPLogonCtrl.Connection)logon.NewConnection();
                //Conn.CodePage = "8400";
                //调用登录方法
                if (Conn.Logon(0, true))
                {
                    label1.Text = "登录成功!";
                }

               //实例SAPFunction对象

                SAPFunctionsOCX.SAPFunctionsClass func = new SAPFunctionsClass();

                //设置连接
                func.Connection = Conn;
               
                SAPFunctionsOCX.IFunction ifunc = (SAPFunctionsOCX.IFunction)func.Add("ZCSMS_GET_HRINFO");
                //设置输入参数
                SAPFunctionsOCX.IParameter BEGDAFROM = (SAPFunctionsOCX.IParameter)ifunc.get_Exports("BEGDAFROM");
                BEGDAFROM.Value = "";
                SAPFunctionsOCX.IParameter BEGDATO = (SAPFunctionsOCX.IParameter)ifunc.get_Exports("BEGDATO");
                BEGDATO.Value = "";
                SAPFunctionsOCX.IParameter MILL = (SAPFunctionsOCX.IParameter)ifunc.get_Exports("MILL");
                MILL.Value = "7960";
                SAPFunctionsOCX.IParameter NUMBERFROM = (SAPFunctionsOCX.IParameter)ifunc.get_Exports("NUMBERFROM");
                NUMBERFROM.Value = "0061500001";
                SAPFunctionsOCX.IParameter NUMBERTO = (SAPFunctionsOCX.IParameter)ifunc.get_Exports("NUMBERTO");
                NUMBERTO.Value = "0061500020";
                //调用RFC方法
                ifunc.Call();
                SAPTableFactoryCtrl.Tables ENQs = (SAPTableFactoryCtrl.Tables)ifunc.Tables;
                SAPTableFactoryCtrl.Table ENQ = (SAPTableFactoryCtrl.Table)ENQs.get_Item("THR");

                int j = ENQ.RowCount;
                DataTable dt = new DataTable();
                for (int i = 1 ;i<=ENQ.RowCount; i ++)
                {
                    DataRow dr = dt.NewRow();
                    if (i == 1)
                    {
                        dt.Columns.Add("MILL");
                        dt.Columns.Add("PERNR");
                        dt.Columns.Add("NAME1");
                        dt.Columns.Add("STEXT");
                    }
                   
                    dr["MILL"] = (String)ENQ.get_Value(i, "MILL");
                    dr["PERNR"] = (String)ENQ.get_Value(i, "PERNR");
                    dr["NAME1"] = (String)ENQ.get_Value(i, "NAME1");
                    dr["STEXT"] = (String)ENQ.get_Value(i, "STEXT");
                    dt.Rows.Add(dr);
                }
                dataGridView1.DataSource = dt.DefaultView; 
        }  
    }
}

 

当然, RFC连接SAP只是其中的方法之一, BAPI等多种方式.

posted @ 2009-03-30 15:11 寒天飞雪 阅读(2280) 评论(10) 编辑

上一篇简单写了vb6.0中访问SAP, 本篇用vb.net实现同样的功能,只是把读取出来的内容存放在数据库中,然后利用GridView显示出来。 当然可以直接存入DataTable或DataSet中直接显示出来。

 

以下见代码示例:

 

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Text
Imports System.Windows.Forms
Imports System.Data.OleDb
Imports System.Xml


Public Class SAPConn
    Public oFunction As Object      ' SAP Functions
    Public oConnection As Object    ' SAP oConnection

    Dim cmd As OleDbCommand
    Dim SqlAd As OleDbDataAdapter
    Dim sql As String

    '测试连接的代码

    Private Sub BtnConnn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnConnn.Click
        Try
            oFunction = CreateObject("SAP.Functions.unicode")
            oConnection = oFunction.Connection
            oConnection.User = "CRMDEV69"
            oConnection.Password = "654321"
            oConnection.System = "CD2"
            oConnection.ApplicationServer = "172.18.95.173"
            oConnection.SystemNumber = 7
            oConnection.Client = "164"
            oConnection.Language = "ZH"

            If oConnection.Logon(0, True) = True Then
                MsgBox("连接成功!")
            Else
                MsgBox("连接失败!")
            End If
        Catch ex As Exception
            MsgBox(ex.ToString(), MsgBoxStyle.Information, "提示")
            Return
        End Try
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim GetCustomers As Object
        Dim Customers As Object
        Dim i As Integer
        Dim sqlstr As String = ""
        ' 通过RFC接口远程运行SAP内部函数ZCSMS_GET_HRINFO
        ' 赋要调用的SAP内建函数名
        Try
            GetCustomers = oFunction.Add("ZCSMS_GET_HRINFO")

           '设置输入参数并赋值
            GetCustomers.Exports("BEGDAFROM") = ""
            GetCustomers.Exports("BEGDATO") = ""
            GetCustomers.Exports("MILL") = "7960"
            GetCustomers.Exports("NUMBERFROM") = "0061500001"
            GetCustomers.Exports("NUMBERTO") = "0061500200"
            Customers = GetCustomers.Tables("THR")

            If GetCustomers.Call Then

               '循环插入到数据库表中
                For i = 1 To Customers.RowCount
                    sqlstr = "Insert into ghy_employee(MILL, PERNR, NAME1, STEXT) values ('" & Customers(i, "MILL") & "','" & Customers(i, "PERNR") & "','" & Customers(i, "NAME1") & "','" & Customers(i, "STEXT") & "' )"

                    Config.ExecAccess(sqlstr)
                Next i
                MsgBox("获取数据成功")
            Else
                MsgBox(" 搜索出错! 出错信息: " + GetCustomers.exception)
            End If
        Catch ex As Exception
            MsgBox(ex.ToString)
            Return
        End Try
      
    End Sub

    '通过GridView显示数据

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        sql = "select * from ghy_employee "
        SqlAd = New OleDbDataAdapter(sql, oConn)
        DS.Clear()

        If DS.Tables.Contains("ghy_employee") Then
            DS.Tables.Remove("ghy_employee")
        End If
        SqlAd.Fill(DS, "ghy_employee")
        DvInvoice.DataSource = DS.Tables("ghy_employee").DefaultView
        DvInvoice.Refresh()
        DvInvoice.ClearSelection()
        DvInvoice.Columns("MILL").HeaderText = "工厂"
        DvInvoice.Columns("PERNR").HeaderText = "员工编号"
        DvInvoice.Columns("NAME1").HeaderText = "员工姓名"
        DvInvoice.Columns("STEXT").HeaderText = "员工部门"
    End Sub
End Class

 

以上两种写法都是利用创建组件OCX的方式进行, 通过调用类的方法进行也可以实现。 缺点是中文无法正常显示。

下一篇文章将贴出C#的例子以研究。

posted @ 2009-03-30 14:52 寒天飞雪 阅读(540) 评论(0) 编辑

最近在研究vb连接SAP的例子, 终于可以正常登录SAP通过RFC读取SAP中的数据。

下面是具体的代码:

vb6.0写法:

 

'定义公共变量

Public Connect As Object
Public Functions As Object

'登录SAP
Private Sub Command1_Click()

   '创建ocx对象
    Set Functions = CreateObject("Sap.Functions.unicode")

   'Sap.Functions.unicode 不加unicode的话无法正常显示中文。这和登录时Language的设置没有关系

   '是因为字符集的原因。

   '设置连接信息
    Set Connect = Functions.Connection
    Connect.ApplicationServer = "172.18.95.173"
    Connect.Client = "169"
    Connect.Language = "ZH"
    Connect.User = "CRMDEV69"
    Connect.Password = "654321"
    Connect.SystemNumber = 7
    Connect.System = "CD2"
   
    If Not Connect.Logon(0, True) Then
      MsgBox "登录失败"

      Command1.SetFocus
    Else 

      Command1.Enabled = False
      MsgBox "登录成功"

    End If
End Sub

'调用RFC的写法

Private Sub Command2_Click()
  Dim GetCustomers As Object
  Dim Customers As Object
  Dim i As Integer

 '所要调用的RFC名称
 Set GetCustomers = Functions.Add("ZCSMS_GET_HRINFO")

 '传递的输入参数名称并赋值

  GetCustomers.Exports("BEGDAFROM") = ""
  GetCustomers.Exports("BEGDATO") = ""
  GetCustomers.Exports("MILL") = "7960"
  GetCustomers.Exports("NUMBERFROM") = "0061500001"
  GetCustomers.Exports("NUMBERTO") = "0061500080"
 
  '执行后返回的Table,相当于二维数组
  Set Customers = GetCustomers.Tables("THR")

 '简单的MsgBox弹出以查看值 

 If GetCustomers.Call Then
    For i = 1 To Customers.RowCount
      MsgBox Customers(i, "MILL")
      MsgBox Customers(i, "PERNR")
      MsgBox Customers(i, "NAME1")
      MsgBox Customers(i, "STEXT")
    Next i
  Else
    MsgBox " 函数调用失败" + GetCustomers.exception
  End If
End Sub

posted @ 2009-03-30 14:40 寒天飞雪 阅读(589) 评论(0) 编辑

核心代码:

 

Imports System.Data.SqlClient

Public Class Form1
    Inherits System.Windows.Forms.Form
    Private ds As New DataSet()

    ' AddTree递归函数每次都要用到数据集中的一个表,所以定义成private
#Region " Windows 窗体设计器生成的代码 "

    Public Sub New()
        MyBase.New()

        '该调用是 Windows 窗体设计器所必需的。
        InitializeComponent()

        '在 InitializeComponent() 调用之后添加任何初始化

    End Sub

    '窗体重写处置以清理组件列表。
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Windows 窗体设计器所必需的
    Private components As System.ComponentModel.IContainer

    '注意:以下过程是 Windows 窗体设计器所必需的
    '可以使用 Windows 窗体设计器修改此过程。
    '不要使用代码编辑器修改它。
    Friend WithEvents TreeView1 As System.Windows.Forms.TreeView
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents Button2 As System.Windows.Forms.Button
    Friend WithEvents ImageList1 As System.Windows.Forms.ImageList
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container
        Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(Form1))
        Me.TreeView1 = New System.Windows.Forms.TreeView
        Me.ImageList1 = New System.Windows.Forms.ImageList(Me.components)
        Me.Button1 = New System.Windows.Forms.Button
        Me.Button2 = New System.Windows.Forms.Button
        Me.SuspendLayout()
        '
        'TreeView1
        '
        Me.TreeView1.ImageIndex = 0
        Me.TreeView1.ImageList = Me.ImageList1
        Me.TreeView1.Location = New System.Drawing.Point(0, 0)
        Me.TreeView1.Name = "TreeView1"
        Me.TreeView1.SelectedImageIndex = 0
        Me.TreeView1.Size = New System.Drawing.Size(272, 476)
        Me.TreeView1.TabIndex = 0
        '
        'ImageList1
        '
        Me.ImageList1.ImageStream = CType(resources.GetObject("ImageList1.ImageStream"), System.Windows.Forms.ImageListStreamer)
        Me.ImageList1.TransparentColor = System.Drawing.Color.Transparent
        Me.ImageList1.Images.SetKeyName(0, "")
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(288, 16)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(75, 23)
        Me.Button1.TabIndex = 1
        Me.Button1.Text = "打开窗体二"
        '
        'Button2
        '
        Me.Button2.Location = New System.Drawing.Point(288, 48)
        Me.Button2.Name = "Button2"
        Me.Button2.Size = New System.Drawing.Size(75, 23)
        Me.Button2.TabIndex = 2
        Me.Button2.Text = "Button2"
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(6, 14)
        Me.ClientSize = New System.Drawing.Size(376, 488)
        Me.Controls.Add(Me.Button2)
        Me.Controls.Add(Me.Button1)
        Me.Controls.Add(Me.TreeView1)
        Me.Name = "Form1"
        Me.Text = "用存储过程加载树"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' '定义数据库连接

        Dim CN As New SqlConnection()
        Try

            '初始化连接字符串
            CN.ConnectionString = "data source =255.255.255.255;initial catalog=baobiaopri;persist security info=False;user id=sa;Password=admin@sa;"
            CN.Open()
            '添加命令,从数据库中得到数据
            Dim sqlCmd As New SqlCommand()

            sqlCmd.Connection = CN
            Dim sql As String = ""
            'sql = "select '1' as privilegeid , 'http://home.ghy.com.cn/ReportServer' as formname , '业务报表' as description ,  0 as parentid"
            'sql = sql + " union  all "
            'sql = sql + " select '2' as privilegeid , 'http://home.ghy.com.cn/ReportServer' as formname , '处理过的表单' as description ,  0 as parentid"
            'sql = sql + " union all"

            'sql = sql + " select '3' as privilegeid , 'http://home.ghy.com.cn/ReportServer' as formname , '我提交的表单' as description ,  0 as parentid"
            'sql = sql + " union all"

            'sql = sql + " select '4' as privilegeid , 'http://home.ghy.com.cn/ReportServer' as formname , '其他可访问的表单' as description ,  0 as parentid"
            'sql = sql + " union all"

            'sql = sql + " select '5' as privilegeid , 'http://home.ghy.com.cn/ReportServer' as formname , '任务夹' as description ,  0 as parentid"
            'sql = sql + " union all"

            'sql = sql + " select '6' as privilegeid , 'http://home.ghy.com.cn/ReportServer' as formname , '子子菜单' as description ,  1002 as parentid"
            'sql = sql + " union all"

            'sql = sql + " select '7' as privilegeid , 'http://home.ghy.com.cn/ReportServer' as formname , '子子菜单' as description ,  6 as parentid"
            'sql = sql + " union all"

            'sql = sql + " select '8' as privilegeid , 'http://home.ghy.com.cn/ReportServer' as formname , '子子子菜单' as description ,  7 as parentid"
            'sql = sql + " union all"

            sql = sql + " select Privileges.PrivilegeID, Privileges.formname , Privileges.description, Privileges.ParentID  "
            sql = sql + " from Privileges inner join User_Privileges  on Privileges.Privilegeid = User_Privileges.Privilegeid"
            sql = sql + " where User_Privileges.userid = 'yinqingyue' order by Privileges.PrivilegeID"

            sqlCmd.CommandText = sql
            'sqlCmd.CommandText = "select * from tbtree"


            sqlCmd.CommandType = CommandType.Text

            Dim adp As SqlDataAdapter = New SqlDataAdapter(sqlCmd)

            adp.Fill(ds)

        Catch ex As Exception

            MsgBox(ex.Message)

        Finally
            CN.Close()
        End Try

        '调用递归函数,完成树形结构的生成
        AddTree(0, Nothing)
    End Sub

    '递归添加树的节点
    Private Sub AddTree(ByVal ParentID As Integer, ByVal pNode As TreeNode)
        Dim Node As TreeNode
        Dim dvTree As New DataView()
        dvTree = New DataView(ds.Tables(0))

        '过滤ParentID,得到当前的所有子节点
        dvTree.RowFilter = "PARENTID = " + ParentID.ToString

        Dim Row As DataRowView
        For Each Row In dvTree
            If pNode Is Nothing Then  '判断是否根节点
                '添加根节点
                'Node = TreeView1.Nodes.Add(Row("context").ToString())
                Node = TreeView1.Nodes.Add(Row("Description").ToString())

                '再次递归
                AddTree(Int32.Parse(Row("PrivilegeID").ToString()), Node)
            Else
                '添加当前节点的子节点
                Node = pNode.Nodes.Add(Row("Description").ToString())
                '再次递归
                AddTree(Int32.Parse(Row("PrivilegeID").ToString()), Node)
            End If
            Node.EnsureVisible()
        Next
    End Sub
End Class

posted @ 2008-12-29 15:18 寒天飞雪 阅读(794) 评论(0) 编辑

MPS:
主生产计划的对象是产成品或关键零部件。主生产计划的目的是降低库存(包括在制品)成本和提高计划的稳定性。在下列情况下,主生产计划是必须的:
        为了确保物料不出现短缺,输入了不同的缓冲时间和安全库存,这不可避免导致了高库存水平。因此尤其对于高价值的物料会出现高仓储成本。
        这些物料的主计划极大地影响成个生产流程:相关组件的计划依赖于产成品或关键零部件的计划结果,即使各产品之间的所有物料很少相同也是这样。在最终产品层次上的计划频繁变更,会导致物料需求计划运行不稳定。
因此,特别关注各成品和关键零部件的计划是很有意义的。这些物料可以作为主计划项目在SAP系统中被标识,它可以使用主生产计划工具安排计划和调整。对这些"主计划项目"的计划导致库存水平的减少并同时提高交货性能和使服务水平更为可靠。

MRP:
物料需求计划(MRP)的主要功能是保证物料的可用性,系统计算在什么时间需要采购或生产多少数量,以保证满足需求。MRP检查库存和需求,产生用于采购和生产的计划定单或采购请求。
物料需求计划(MRP)的目的是一方面保证不出现短缺,一方面尽量使成本和资金占用最小化。

------------------------------------------------------------------------------------

mps是物料主计划,主要针对的是生产过程中的主要原材料或者半成品等,比如特别贵重的,或者对于保质期限要求特别严格的,比较难以实现备料的物料等
mrp是只物料需求计划,则针对生产过程中的所有物料
我们可以在运行mrp之前运行一次mps,如果mps不满足的话,则不需要运行mrp了~

--------------------------------------------------------------------------------------

MRP有三种: MPS、MRP、基本消费计划
MPS包含:M0、M1、M2、M3、M4
MRP包含:PD、P1、P2、P3、P4
基于消费计划包含:重订货点、基于预测计划、基于时间物料计划
如果物料主数据维护为M0、M1、M2、M3、M4等MPS类型,那么用MD40,MD41,MD42,MDBS等事务码来运行;MRP类型物料用MD01,MD02,MD03,MD43,MDBT等事务码来运行。

如果使用MD40或者MDBS运行MPS物料时候,可以选择是否同时运行下层MRP物料。

不管MPS物料还是MRP物料,运行的原理都是相同的,都是依照我们俗称的MRP逻辑计算。

理论上将MPS执行到成品层次,而MRP执行到成品以下的物料层次,但不同的企业或产品性子性质可以采用MPS或MRP,比如:系统排出的计划订单如果不需要再次人为调整,应该使用MPS,否则,应使用MRP即可

 

posted @ 2008-12-02 16:12 寒天飞雪 阅读(446) 评论(0) 编辑
 

今天同事问了我一个SQL的问题,关于SQL Server内部存储结构的,我觉得挺有意思,所以写下这篇博客讨论并归纳了一下。问题是这样的:

首先我们创建两张表,一张表的列长度是4039字节,另一张表的长度是4040字节,他们就只有一个字节的差距,比如以下创建表的SQL

CREATE TABLE tb4039(c1 INT IDENTITY,c2 char(4035not null)
CREATE TABLE tb4040(c1 INT IDENTITY,c2 char(4036not null)

 

由于INT类型是4个字节,所以我们创建的tb4039表有4+4035=4039个字节的长度,tb4040中的c2字段比tb4039中的c2字段多了一个字节,总长度是4040字节,其他没有区别了。接下来是向这两个表中插入数据,比如插入100条数据,SQL语句是:

DECLARE @i INT
SET @i=1
WHILE @i<=100
BEGIN
    
INSERT INTO tb4039 (c2) VALUES('test'+CONVERT(VARCHAR(5),@i));
    
INSERT INTO tb4040 (c2) VALUES('test'+CONVERT(VARCHAR(5),@i));
    
SET @i=@i+1
END

 

好,现在我们使用SSMS来查看一下这两个表的空间占用量,如果是SQL2005,那么可以使用SSMS自带的报表查看,如果是SQL2008,那么直接使用对象资源管理器详细信息界面进行查看(如果使用的是SQL2008而不知道怎么查看表空间使用量那么请查看我以前写的一篇博客:SQL Server 2008新特性之SSMS增强)。我这里使用的是SQL2008,查看到的情况如图:

当然,我们也可以使用T-SQL来查询系统视图,得出这两个表的数据占用的空间,查询代码为:

SELECT OBJECT_NAME(i.object_idAS TableName,data_pages*8 AS DataSize --这里返回的是数据页个数,1页是8K,所以乘以8
FROM sys.indexes as i
JOIN sys.partitions as p ON p.object_id = i.object_id and p.index_id = i.index_id
JOIN sys.allocation_units as a ON a.container_id = p.partition_id
where i.object_id=OBJECT_ID('tb4039'OR i.object_id=OBJECT_ID('tb4040')

 

系统返回结果:

TableName    DataSize
tb4039           400
tb4040           800

和我们通过报表或者SSMS查看到的结果相同,两个表只相差了一个字节,可是一个占用了400K的存储空间,另一个却占用了800K的存储空间,是另一个表的双倍!!!

一个字节的差距就造成了存储空间成倍的增加,为什么会这样呢?这就要从SQL Server存储结构讲起。

------------------------------------------------华丽的分割线,进入主题-----------------------------------------------------------------

SQL Server最小的存储单位是页(Page),一个页的大小是8K=8192字节。一个数据页是由3部分组成:页头、数据行和行偏移矩阵,具体结构如图:

页头保存了页的编号、上一页ID、下一页ID、可以字节数等等关于该页的基本信息。页头的大小是固定的96个字节,所以剩下8192-96=8096个字节用于存储数据行和行偏移矩阵。

行偏移矩阵在页的最后面,而且是倒序排列的,使用2个字节来表示数据行在页面内部的偏移量,有1行数据则行偏移矩阵的大小是2字节,有2行数据则行偏移矩阵的大小是4字节,以此类推。

除了页头占用的空间和行偏移矩阵占用的空间,中间剩下的空间就是给数据行使用的。假设我们要在一个页中保存2行数据,那么这2行数据可以使用8096-4=8092个字节的空间,也就是说1行数据可以使用8092/2=4046个字节的空间。这里的4046个字节并不是完全都用来保存数据行,一个数据行中还存在其他的信息用于表示该行数据,具体的结构是这样的:

状态位A

状态位B

定长数据类型的长度

定长数据的内容

列数

NULL位图

变长列的个数

变长列的偏移矩阵

变长列的数据

1字节

1字节

2字节

具体定长数据字节

2字节

列数/8个字节

2字节

变长列个数*2个字节

具体变长数据字节

不管我们对表的定义是多么的简单,一行数据除了数据自身占用的空间外,至少还要占用1+1+2+2+1=7个字节。如果定义的数据列很多,或者里面有变长数据列,那么占用的空间可能会更多。

现在回到我们前面讲到的2个表tb4039tb4040,要存储tb4039中的一行数据需要1+1+2+4039+2+1=4046字节,所以正好可以在一个页中保存2行数据。所以插入了100行数据,实际上是保存在50个数据页中,大小就是8K*50=400K。而对于tb4040表,要存储一行数据需要4047个字节,没法在一个页中保存2行数据,所以一行数据就占用一个数据页,100行数据占用了100个数据页,大小就是8K*100=800K

--------------------------------------------做了一堆加减乘除,下面总结下--------------------------------------------

这里只是举了一个极端的例子,所以造成了一个字节的偏差而使占用的存储空间翻倍,在实际应用中很少会出现这么极端的情况,但是很有可能使一个页存储5条数据的因为某个列多了12个字节所以只能存储4条数据。也许大家认为少存一条数据并没有什么,但是在数据量变的非常庞大以后一页4条数据和一页5条数据将会产生明显的性能差异。使得一页中存放更多的数据并不是为了节约存储成本,现在的硬盘已经很便宜了很多服务器都是几百个G的硬盘,本来5G的数据现在变长了10G,相对几百个GT的硬盘来说又算得了什么。

实际上我们要让一个数据页中存放更多行的数据主要是出于性能的考虑。SQL Server进行数据库读写操作的基本单位是页,如果一页中存放了更多的数据,那么对表进行扫描和查找时进行的IO操作将减少,毕竟IO操作是非常消耗时间影响性能的。假设tb4039中有100W条数据,那么进行全表扫描就要读取50W个数据页,如果读取10W个数据页花费1秒钟,那么对表tb4039进行扫描需要花费5秒钟时间,而如果是使用tb4040存储这100W条数据,进行全表扫描则需要读取100W个数据页,总共花费10秒钟时间。就一个字节的差别,一个是5秒另一个是10秒,对性能的影响非常明显。

为了提高数据库查询的性能,在表设计时可以遵循以下建议:

·                                                                                 主键尽可能的短,能用tinyint的就不要用int,能用char(5)的就不要用成varchar(50)

·                                                                                 计算好表列的长度,能够在一个页中存放5条数据的,那就不要将字段设置的太长使得一个页中只能存放3条或者4条数据。

·                                                                                 尽量将字段设置为不允许为NULL,因为NULL值在存储和数据处理时系统需要专门的处理,降低了性能。

·                                                                                 能够用固定长度的就不要用变长字段,比如身份证号就可以使用CHAR(18),而不应该使用VARCHAR(18)

·                                                                                 不要在一个表中建立太多的列,如果一个实体的属性太多时可以考虑进行垂直分割,将常用的字段放在一个表,不常用的字段放另外的表,这样可以减小常用字段表中数据列占用的空间,使得一个数据页中存储更多的数据行。

·                                                                                 不要将大对象、长字符串和常用的字段放在同一个表中。同样还是出于性能上的考虑,比如有个产品表,里面有产品ID、产品名字、产品售价、产品图片、产品描述等字段,那么我们可以将产品ID、产品名字、产品售价这几个常用的而且占用空间小的列放在一个表,然后建立产品ID、产品图片、产品描述这样的表,通过外键约束的方式将大对象数据和长字符串数据放在另一个表中。

posted @ 2008-12-02 15:06 寒天飞雪 阅读(324) 评论(2) 编辑
摘要: 转载自: http://www.regexlab.com/zh/regref.htm引言 正则表达式(regular expression)就是用一个“字符串”来描述一个特征,然后去验证另一个“字符串”是否符合这个特征。比如 表达式“ab+” 描述的特征是“一个 'a' 和 任意个 'b' ”,那么 '...阅读全文
posted @ 2008-12-02 15:04 寒天飞雪 阅读(126) 评论(1) 编辑
摘要: 利用 System.Data.OracleClient.Dll 的组件进行连接:首先配置WebConfig 文件;<connectionStrings> <add name="oracleconn" connectionString="Data Source="";User ID=ryq;Password=123456" providerName="System.Data.Ora...阅读全文
posted @ 2008-08-04 10:22 寒天飞雪 阅读(745) 评论(0) 编辑