2009-02-18 6 views
15

Ho un elenco come:Qual è il modo migliore per recuperare valori distinti/univoci usando SPQuery?

Movie   Year 
-----   ---- 
Fight Club  1999 
The Matrix  1999 
Pulp Fiction 1994 

Utilizzando CAML e l'oggetto SPQuery ho bisogno di ottenere un elenco distinto di voci dalla colonna Anno, che popoleranno un menu a discesa di controllo.

La ricerca in giro non sembra essere un modo per farlo all'interno della query CAML. Mi chiedo come sono andate le persone a realizzare questo?

risposta

13

Un altro modo per farlo è quello di utilizzare DataView.ToTable-Metodo - il primo parametro è quello che fa la lista distinta.

  SPList movies = SPContext.Current.Web.Lists["Movies"]; 
      SPQuery query = new SPQuery(); 
      query.Query = "<OrderBy><FieldRef Name='Year' /></OrderBy>"; 

      DataTable tempTbl = movies.GetItems(query).GetDataTable(); 
      DataView v = new DataView(tempTbl); 
      String[] columns = {"Year"}; 
      DataTable tbl = v.ToTable(true, columns); 

Si può quindi procedere con il TBL DataTable.

+2

Anche se questo è stato contrassegnato come la risposta, questo metodo si basa ancora sul recupero di ogni elemento della lista dal database e * poi * trovare i valori univoci. Penso che l'intero punto di chiedere come farlo in CAML è di evitare di recuperare ogni elemento dal database ... – MgSam

+2

Sono d'accordo con MgSam, tuttavia, poiché CAML non è un vero sostituto di un vero linguaggio di query come SQL. Questo è buono come si arriva. E questa risposta sposta la conversazione in avanti. +1 da me. –

2

Non c'è DISTINCT in CAML per popolare il menu a discesa provare a utilizzare qualcosa come:

foreach (SPListItem listItem in listItems) 
    { 
     if (null == ddlYear.Items.FindByText(listItem["Year"].ToString())) 
     { 
        ListItem ThisItem = new ListItem(); 
        ThisItem.Text = listItem["Year"].ToString(); 
        ThisItem.Value = listItem["Year"].ToString(); 
        ddlYear.Items.Add(ThisItem); 
     } 
    } 

presuppone che il menu a discesa è chiamata ddlYear.

1

È possibile passare da SPQuery a SPSiteDataQuery? Dovresti essere in grado di, senza problemi.

Dopo di che, è possibile utilizzare il comportamento ado.net di serie:

SPSiteDataQuery query = new SPSiteDataQuery(); 
/// ... populate your query here. Make sure you add Year to the ViewFields. 

DataTable table = SPContext.Current.Web.GetSiteData(query); 

//create a new dataview for our table 
DataView view = new DataView(table); 

//and finally create a new datatable with unique values on the columns specified 

DataTable tableUnique = view.ToTable(true, "Year"); 
5

Se si desidera associare i risultati distinti a un DataSource di ad esempio un ripetitore e conservare l'elemento effettivo tramite il metodo e.Item.DataItem degli eventi ItemDataBound, la modalità DataTable non funzionerà. Invece, e inoltre anche quando non vuoi collegarlo a un DataSource, puoi anche usare Linq per definire i valori distinti.

// Retrieve the list. NEVER use the Web.Lists["Movies"] option as in the other examples as this will enumerate every list in your SPWeb and may cause serious performance issues 
var list = SPContext.Current.Web.Lists.TryGetList("Movies"); 

// Make sure the list was successfully retrieved 
if(list == null) return; 

// Retrieve all items in the list 
var items = list.GetItems(); 

// Filter the items in the results to only retain distinct items in an 2D array 
var distinctItems = (from SPListItem item in items select item["Year"]).Distinct().ToArray() 

// Bind results to the repeater 
Repeater.DataSource = distinctItems; 
Repeater.DataBind(); 

Ricorda che poiché non v'è alcun supporto per le query CAML distinti, ogni campione fornite in questa pagina troverà tutti gli elementi dalla SPList. Questo può andar bene per le liste più piccole, ma per le liste con migliaia di listini, questo sarà seriamente un killer delle prestazioni. Sfortunatamente non esiste un modo più ottimizzato per ottenere lo stesso risultato.

0

Stavo considerando questo problema prima di oggi, e la soluzione migliore che potevo pensare utilizza il seguente algoritmo (mi dispiace, nessun codice al momento):

L is a list of known values (starts populated with the static Choice options when querying fill-in options, for example) 
X is approximately the number of possible options 

1. Create a query that excludes the items in L 
1. Use the query to fetch X items from list (ordered as randomly as possible) 
2. Add unique items to L 
3. Repeat 1 - 3 until number of fetched items < X 

Ciò ridurrebbe il numero totale di elementi restituiti significativamente, al costo di fare più domande.

Non importa se X è completamente preciso, ma la casualità è molto importante. In sostanza, è probabile che la prima query includa le opzioni più comuni, quindi la seconda query le escluderà ed è probabile che includa le prossime opzioni più comuni e così via attraverso le iterazioni.

Nel migliore dei casi, la prima query include tutte le opzioni, quindi la seconda query sarà vuota. (X elementi recuperati in totale, oltre 2 query)

Nel peggiore dei casi (ad esempio, la query è ordinata dalle opzioni che stiamo cercando e ci sono più di X elementi con ciascuna opzione) faremo come molte domande quante sono le opzioni. Restituzione di circa X * X elementi in totale.

0

Dopo aver trovato post dopo post su come ciò fosse impossibile, ho finalmente trovato un modo. Questo è stato testato in SharePoint Online. Ecco una funzione che ti darà tutti i valori univoci per una colonna. Richiede solo di passare nell'elenco Id, ID vista, nome elenco interno e funzione di richiamata.

function getUniqueColumnValues(listid, viewid, column, _callback){ 
var uniqueVals = []; 
$.ajax({ 
    url: _spPageContextInfo.webAbsoluteUrl + "/_layouts/15/filter.aspx?ListId={" + listid + "}&FieldInternalName=" + column + "&ViewId={" + viewid + "}&FilterOnly=1&Filter=1", 
    method: "GET", 
    headers: { "Accept": "application/json; odata=verbose" } 
    }).then(function(response) { 
     $(response).find('OPTION').each(function(a,b){ 
      if ($(b)[0].value) { 
       uniqueVals.push($(b)[0].value); 
      } 
     }); 
     _callback(true,uniqueVals); 
},function(){ 
    _callback(false,"Error retrieving unique column values"); 
}); 

}