Compilazione di Datagrid e query SQL
Domanda
Ho 3 tabelle nel database mostrate di seguito. E voglio fare un rapporto proprio come mostrato sotto link. Come posso farlo con Datagrid o Datalist? Qual è la scelta migliore? Ho provato a farlo per una settimana.
AZIENDA : ID_COMPANY, COMPANY_NAME
PRODOTTO : ID_PRODUCT, PRODUCT_NAME
PRODUCT_SALE : ID_COMPANY, ID_PRODUCT, SALE_COUNT
Aggiornato :
Potrei farlo, con i tuoi aiuti. Tuttavia ora ho anche un piccolo problema.
Quando scrivo una query con pivot, il nome dei prodotti diventa intestazione di colonna. se la lunghezza del nome di un prodotto è superiore a 30 caratteri, Oracle non lo accetta come intestazione di colonna. Quindi ho ritagliato e reso i nomi dei prodotti 30 caratteri per risolvere questo problema. Successivamente si è verificato anche un problema.
Quando ritaglio il nome del prodotto di 30 caratteri, alcuni prodotti diventano lo stesso nome e "ORA-00918: colonna definita ambiguamente" si è verificato un messaggio di errore.
In questo caso cosa si può fare?
Soluzione
Utilizza una query sql standard (i pivot sono costosi in termini di prestazioni) e crea una funzione pivot personalizzata nel tuo codice lato server. Ecco un paio di esempi.
''' <summary>
''' Pivots columnX as new columns for the X axis (must be unique values) and the remaining columns as
''' the Y axis. Optionally can include columns to exclude from the Y axis.
''' </summary>
''' <param name="dt"></param>
''' <param name="columnX"></param>
''' <param name="columnsToIgnore"></param>
''' <returns>DataTable</returns>
''' <remarks></remarks>
Public Shared Function Pivot(ByVal dt As DataTable, ByVal columnX As String, ByVal ParamArray columnsToIgnore As String()) As DataTable
Dim dt2 As New DataTable()
If columnX = "" Then
columnX = dt.Columns(0).ColumnName
End If
'Add a Column at the beginning of the table
dt2.Columns.Add(columnX)
'Read all DISTINCT values from columnX Column in the provided DataTable
Dim columnXValues As New List(Of String)()
'Create the list of columns to ignore
Dim listColumnsToIgnore As New List(Of String)()
If columnsToIgnore.Length > 0 Then
listColumnsToIgnore.AddRange(columnsToIgnore)
End If
If Not listColumnsToIgnore.Contains(columnX) Then
listColumnsToIgnore.Add(columnX)
End If
' Add the X axis columns
For Each dr As DataRow In dt.Rows
Dim columnXTemp As String = dr(columnX).ToString()
If Not columnXValues.Contains(columnXTemp) Then
columnXValues.Add(columnXTemp)
dt2.Columns.Add(columnXTemp)
Else
Throw New Exception("The inversion used must have unique values for column " + columnX)
End If
Next
'Add a row for each non-columnX of the DataTable
For Each dc As DataColumn In dt.Columns
If Not columnXValues.Contains(dc.ColumnName) AndAlso Not listColumnsToIgnore.Contains(dc.ColumnName) Then
Dim dr As DataRow = dt2.NewRow()
dr(0) = dc.ColumnName
dt2.Rows.Add(dr)
End If
Next
'Complete the datatable with the values
For i As Integer = 0 To dt2.Rows.Count - 1
For j As Integer = 1 To dt2.Columns.Count - 1
dt2.Rows(i)(j) = dt.Rows(j - 1)(dt2.Rows(i)(0).ToString()).ToString()
Next
Next
Return dt2
End Function
''' <summary>
''' Can pivot any column as X, any column as Y, and any column as Z. Sort on X, sort on Y and optionally, the
''' values at the intersection of x and y (Z axis) can be summed.
''' </summary>
''' <param name="dt"></param>
''' <param name="columnX"></param>
''' <param name="columnY"></param>
''' <param name="columnZ"></param>
''' <param name="nullValue"></param>
''' <param name="sumValues"></param>
''' <param name="xSort"></param>
''' <param name="ySort"></param>
''' <returns>DataTable</returns>
''' <remarks></remarks>
Public Shared Function Pivot(ByVal dt As DataTable, ByVal columnX As String, ByVal columnY As String, ByVal columnZ As String, _
ByVal nullValue As String, ByVal sumValues As Boolean, ByVal xSort As Sort, ByVal ySort As Sort) As DataTable
Dim dt2 As New DataTable()
Dim tickList As List(Of Long) = Nothing
If columnX = "" Then
columnX = dt.Columns(0).ColumnName
End If
'Add a Column at the beginning of the table
dt2.Columns.Add(columnY)
'Read all DISTINCT values from columnX Column in the provided DataTable
Dim columnXValues As New List(Of String)()
Dim cols As Integer = 0
For Each dr As DataRow In dt.Rows
If dr(columnX).ToString.Contains("'") Then
dr(columnX) = dr(columnX).ToString.Replace("'", "")
End If
If Not columnXValues.Contains(dr(columnX).ToString) Then
'Read each row value, if it's different from others provided,
'add to the list of values and creates a new Column with its value.
columnXValues.Add(dr(columnX).ToString)
End If
Next
'Sort X if needed
If Not xSort = Sort.None Then
columnXValues = SortValues(columnXValues, xSort)
End If
'Add columnX
For Each s As String In columnXValues
dt2.Columns.Add(s)
Next
'Verify Y and Z Axis columns were provided
If columnY <> "" AndAlso columnZ <> "" Then
'Read DISTINCT Values for Y Axis Column
Dim columnYValues As New List(Of String)()
For Each dr As DataRow In dt.Rows
If dr(columnY).ToString.Contains("'") Then
dr(columnY) = dr(columnY).ToString.Replace("'", "")
End If
If Not columnYValues.Contains(dr(columnY).ToString()) Then
columnYValues.Add(dr(columnY).ToString())
End If
Next
' Now we can sort the Y axis if needed.
If Not ySort = Sort.None Then
columnYValues = SortValues(columnYValues, ySort)
End If
'Loop all Distinct ColumnY Values
For Each columnYValue As String In columnYValues
'Create a new Row
Dim drReturn As DataRow = dt2.NewRow()
drReturn(0) = columnYValue
Dim rows As DataRow() = dt.[Select](columnY + "='" + columnYValue + "'")
'Read each row to fill the DataTable
For Each dr As DataRow In rows
Dim rowColumnTitle As String = dr(columnX).ToString()
'Read each column to fill the DataTable
For Each dc As DataColumn In dt2.Columns
If dc.ColumnName = rowColumnTitle Then
'If sumValues, try to perform a Sum
'If sum is not possible due to value types, use the nullValue string
If sumValues Then
If IsNumeric(dr(columnZ).ToString) Then
drReturn(rowColumnTitle) = Val(drReturn(rowColumnTitle).ToString) + Val(dr(columnZ).ToString)
Else
drReturn(rowColumnTitle) = nullValue
End If
Else
drReturn(rowColumnTitle) = dr(columnZ).ToString
End If
End If
Next
Next
dt2.Rows.Add(drReturn)
Next
Else
Throw New Exception("The columns to perform inversion are not provided")
End If
'if nullValue param was provided, fill the datable with it
If nullValue <> "" Then
For Each dr As DataRow In dt2.Rows
For Each dc As DataColumn In dt2.Columns
If dr(dc.ColumnName).ToString() = "" Then
dr(dc.ColumnName) = nullValue
End If
Next
Next
End If
Return dt2
End Function
''' <summary>
''' Sorts a list of strings checking to see if they are numeric or date types.
''' </summary>
''' <param name="list"></param>
''' <param name="srt"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Shared Function SortValues(ByVal list As List(Of String), ByVal srt As Sort) As List(Of String)
Dim tickList As List(Of Long) = Nothing
Dim dblList As List(Of Double) = Nothing
' Figure out how to sort columnX
For Each s As String In list
Dim colDate As Date = Nothing
If Date.TryParse(s, colDate) Then
tickList = New List(Of Long)
Exit For
End If
Next
Dim dateTicks As Long
If Not tickList Is Nothing Then
For Each s As String In list
dateTicks = DateTime.Parse(s).Ticks
If Not tickList.Contains(dateTicks) Then
tickList.Add(dateTicks)
End If
Next
If srt = Sort.DESC Then
tickList.Sort()
tickList.Reverse()
ElseIf srt = Sort.ASC Then
tickList.Sort()
End If
list.Clear()
For Each lng As Long In tickList
list.Add(New Date(lng).ToString("G"))
Next
Else
Dim dbl As Double = Nothing
For Each s As String In list
If IsNumeric(s) Then
dblList = New List(Of Double)
End If
Next
If Not dblList Is Nothing Then
'Doubles or Integers
For Each s As String In list
dbl = Val(s)
If Not dblList.Contains(dbl) Then
dblList.Add(dbl)
End If
Next
If srt = Sort.DESC Then
dblList.Sort()
dblList.Reverse()
ElseIf srt = Sort.ASC Then
dblList.Sort()
End If
list.Clear()
For Each d As Double In dblList
list.Add(d.ToString)
Next
Else
'Strings
If srt = Sort.DESC Then
list.Sort()
list.Reverse()
ElseIf srt = Sort.ASC Then
list.Sort()
End If
End If
End If
Return list
End Function
Altri suggerimenti
Quale versione di SQL stai eseguendo? L'uso di PIVOT potrebbe essere un modo rapido per ottenere i dati nel modulo desiderato, quindi puoi utilizzare il generico DataGrid per visualizzare i dati nel suo (quasi) "grezzo" form - ovvero il modo in cui i dati vengono presentati dal server SQL. Potresti quindi pensare a DataGrid più come un foglio di calcolo che come rappresentante di una tabella di dati come si trova in un database.
Ecco un buon documento introduttivo su come utilizzare PIVOT per rappresentare i dati nel modulo che stai cercando:
http://www.tsqltutorials.com/pivot.php
Certo, penso che questo potrebbe essere disponibile solo in SQL 2005 ... quindi se stai usando una versione precedente questo potrebbe non essere d'aiuto.
Aggiornato:
Su Oracle 10g avrai bisogno dell'estensione MODELLO, non è un mondo diverso da PIVOT in SQL ma ovviamente Oracle 10g fa le cose a modo suo: Controlla questo link
Mi sembra un report a campi incrociati. Hai 2 opzioni per andare su questo
- Ruota i dati nel database e associali a un datagrid. L'esatta sintassi di ciò varierà in base al motore di database che stai utilizzando. Ecco un esempio in SQL
- Utilizza uno strumento di reporting in grado di eseguire tabulazioni incrociate basate su un semplice join, come SQL Reporting Services, Crystal Reports, XtraReports, ecc.
Su Oracle 10g avrai bisogno dell'estensione MODEL, non è un mondo diverso da PIVOT in SQL ma ovviamente Oracle 10g fa le cose a modo suo:
http: // tecnologia .amis.nl / blog / 300 / perno-in-sql-con-il-10g-model-clausola
Di seguito funzionerà se i numeri di prodotto sono statici:
<asp:gridview>
<columns>
<asp:boundfield datafield="companyname" itemstyle-headertext="" />
<asp:boundfield datafield="SALE_COUNT" itemstyle-headertext='<%# FunctionToLoadurproduct(product1) %>' />
<asp:boundfield datafield="SALE_COUNT" itemstyle-headertext='<%# FunctionToLoadurproduct(product1) %>' />
and so on...
</columns>
</gridview >
Gestisci le vendite del prodotto in base all'ID del prodotto nella tua query utilizzando query in linea.
Usa il controllo ripetitori nidificati. Il ripetitore esterno ripeterà le Aziende e l'interno ripeterà i Prodotti.