2009-03-26 8 views
1

J'ai une requête pour retourner des lignes distinctes aléatoires d'une base de données Access. Voici la requête:Pourquoi AccessDataSource renvoie-t-il des résultats différents à interroger dans Access?

SELECT * FROM 
(SELECT DISTINCT m.MemberID, m.Title, m.FullName, m.Address, 
     m.Phone, m.EmailAddress, m.WebsiteAddress FROM Members AS m INNER JOIN MembersForType AS t ON m.MemberID = t.MemberID WHERE 
(Category = 'MemberType1' OR Category = 'MemberType2')) as Members 
ORDER BY RND(members.MemberID) DESC 

Quand je lance ce dans Access, il renvoie les lignes dans un ordre différent à chaque fois, selon l'ordre de tri aléatoire. Quand je le lance dans mon application Web, les lignes reviennent dans le même ordre à chaque fois. Voici comment je l'appelle dans mon code-behind:

private void BindData() 
{ 
    using (AccessDataSource ds = new AccessDataSource("~/App_Data/mydb.mdb", GetSQLStatement())) 
    { 
     ds.DataSourceMode = SqlDataSourceMode.DataReader; 
     ds.CacheDuration = 0; 
     ds.CacheExpirationPolicy = DataSourceCacheExpiry.Absolute; 
     ds.EnableCaching = false;    
     listing.DataSource = ds.Select(new DataSourceSelectArguments()); 
     listing.DataBind(); 
     if (listing.Items.Count == 0) 
      noResults.Visible = true; 
     else 
      noResults.Visible = false; 
    } 
} 

j'ajouté dans ce genre de choses au sujet de la mise en cache parce que je pensais que la requête était mise en mémoire cache, mais le résultat a été le même. J'ai mis un point d'arrêt dans le code pour m'assurer que la requête était la même que ci-dessus et c'était le cas.

Des idées? Ça me rend dingue.

+0

Est-il retourné avec le même ordre aléatoire ou y a-t-il une sorte d'intelligence dans la commande que vous voyez? –

+0

Semble être le même ordre aléatoire. – Phill

+0

Je vais mettre cela dans un commentaire, comme je suis une idée de dépannage et non une réponse, mais avez-vous essayé d'ajouter "RND (members.MemberID)" à la clause select dans la version web pour voir si elle retourne le même nombre à chaque fois? Une pensée est qu'il optimise le RND() en mettant en cache le résultat. – JohnFx

Répondre

2

Lors de l'exécution de la fonction de ACE/Jet RND contre une nouvelle connexion la même valeur de départ est utilisé à chaque fois. Lorsque vous utilisez MS Access, vous utilisez la même connexion à chaque fois, ce qui explique pourquoi vous obtenez une valeur différente à chaque fois.

Tenir compte de ces exemples VBA: le premier utilise une nouvelle connexion à chaque itération:

Sub TestDiff() 

    Dim con As Object 
    Set con = CreateObject("ADODB.Connection") 
    With con 
    .ConnectionString = _ 
     "Provider=MSDataShape;Data " & _ 
     "Provider=Microsoft.ACE.OLEDB.12.0;" & _ 
     "Data Source=C:\Tempo\Test_Access2007.accdb" 
    .CursorLocation = 3 

    Dim i As Long 
    For i = 0 To 2 

     .Open 
     Debug.Print .Execute("SELECT RND FROM OneRowTable;")(0) 
     .Close 
    Next 
    End With 

End Sub 

Sortie:

0.705547511577606 
0.705547511577606 
0.705547511577606 

Notez la même valeur à chaque fois.

Le deuxième exemple utilise la même connexion à chaque itération (les états .Open et .Close sont déplacés en dehors de la boucle):

Sub TestSame() 

    Dim con As Object 
    Set con = CreateObject("ADODB.Connection") 
    With con 
    .ConnectionString = _ 
     "Provider=MSDataShape;Data " & _ 
     "Provider=Microsoft.ACE.OLEDB.12.0;" & _ 
     "Data Source=C:\Tempo\Test_Access2007.accdb" 
    .CursorLocation = 3 

    .Open 

    Dim i As Long 
    For i = 0 To 2 
     Debug.Print .Execute("SELECT RND FROM OneRowTable;")(0) 
    Next 

    .Close 

    End With 

End Sub 

sortie:

0.705547511577606 
0.533424019813538 
0.579518616199493 

Remarque valeurs différentes à chaque fois .

Dans le code VBA, vous pouvez utiliser le mot-clé Randomize pour amorcer la fonction Rnd() mais je ne pense pas que cela puisse être fait dans ACE/Jet. Une solution de contournement consiste à utiliser la partie décimale la moins significative de la fonction niladic ACE/Jet the NOW() par exemple. quelque chose comme:

SELECT CDBL(NOW()) - ROUND(CDBL(NOW()), 4) FROM OneRowTable 
+0

Vous pouvez être sur quelque chose ici ... J'ai changé le code pour utiliser un OleDbConnection afin qu'il en crée un nouveau à chaque fois et maintenant il fonctionne comme prévu. – Phill

+0

Nouveau code: utiliser (OleDbConnection conn = new OleDbConnection (str) { conn.Open(); commande OleDbCommand = conn.CreateCommand(); Command.CommandText = GetSQLStatement(); listing.DataSource = Command.ExecuteReader() listing.DataBind(); – Phill

+0

Bonne prise sur le RND étant semé à la même chose pour chaque connexion - j'allais suggérer que :-) –

0

Je propose le RND dans le SELECT interne

SELECT * FROM 
    (SELECT DISTINCT m.MemberID, RND(m.MemberID) as SortOrder, m.Title, 
    m.FullName, m.Address, m.Phone, m.EmailAddress, m.WebsiteAddress 
    FROM Members AS m 
    INNER JOIN MembersForType AS t ON m.MemberID = t.MemberID 
    WHERE 
     (Category = 'MemberType1' OR Category = 'MemberType2')) as Members 
ORDER BY 
    Members.SortOrder DESC 
+0

J'ai essayé cela en vain. Même résultat J'obtiens les résultats dans le même ordre (quoique dans un ordre différent d'avant) sur le site Web peu importe combien de fois la page est chargée. Dans Access, les résultats sont classés différemment à chaque fois. – Phill

0

Vous pouvez utiliser le temps comme un argument dans le champ RND

Dim maintenant Comme DateTime = DateTime.Now

Dim millSec As Integer = Now.Millisecond

finalQuery = "SELECT * DE wordInfo ORDER BY Rnd (- (1000 * ROUND (" + millSec.ToString ("N") + ", 0)) * [ID])"

Donc, ici, à partir de la valeur date et heure, valeur milliseconde est pris qui sera entier et il est utilisé dans la requête sql en l'arrondissant.

wordInfo est le nom de la table ID est le nom de la colonne dans la table de base de données

Cela donne un ordre aléatoire à chaque fois (puisque la valeur de milliseconde est différent) que ce soit même connexion ou une nouvelle connexion.

Questions connexes