8
votes

Sélectionnez des groupes distincts de lignes en fonction de la moyenne

J'ai une table t_stats avec colonne ID (int) et colonne ratio (décimal (8,4)) . ID est unique.

Je veux interroger la table t_stats afin de sélectionner 3 groupes avec le même avg (ratio) (le plus proche possible ).

peut être effectué à l'aide de tables temporaires, tant que je peux l'exécuter sous forme de script ou de procédure stockée.


EDIT: Voici l'exemple concret:

entrée: xxx

sortie: xxx

donc je veux faire 3 groupes de n valeurs et viser une valeur moyenne spécifique x . (Exemple avec n = 30 et 0.75 ressemblerait à 3 groupes de 30 valeurs chacun où chaque groupe a 0,75 et un id ne peut appartenir à 1 groupe.)

la moyenne est presque identique dans chaque groupe et près de x : xxx


4 commentaires

C'est comme le problème du vendeur itinérant. Vous auriez besoin de comparer toutes les combinaisons et de choisir le meilleur interprète. Et pour même des jeux de données de taille modérée, il s'agit d'un grand nombre de combinaisons! Sauf si vous êtes heureux de faire une estimation naïve? [commande par taille, les lignes 1-3 vont aux groupes 1-3, puis les rangées 4-6 vont aux groupes 1-3, etc., etc.]


Pour le moment, c'est ce que j'utilise. Mais j'espérais une solution moins naïve.


Vous devez examiner les algorithmes d'optimisation. SQL n'est pas comme le meilleur environnement.


@Dems: j'ai ajouté c # et linq-to-sql sur les balises, si cela peut aider à fournir une solution plus optimisée.


4 Réponses :


2
votes

Essayez ceci xxx

résultat Entrez la description de l'image ici

édité J'ai essayé avec les données Sampel que vous avez fournies (DDL inconnue pour votre référence) xxx

et le résultat est

 Entrez la description de l'image ici

Le temps pris pour l'exécution est de 27 secondes. Veuillez tester de votre fin (aussi le résultat) et laissez-moi savoir.

édité

75 ddl ddl xxx


6 commentaires

Je ne peux pas tester votre solution avec mes données (110 lignes au lieu de 9 sont trop nombreuses lignes pour la clause avec ...). la déclaration terminée. La récursion maximale 100 a été épuisée avant la fin de la déclaration.


J'aimerais essayer de l'essayer et voir les résultats, mais avec une table de 75 rangées, elle fonctionnait pendant 20 minutes et toujours en cours d'exécution. Peut-être que quelqu'un pourrait optimiser votre solution?


Pourriez-vous s'il vous plaît me donner les données avec la sortie respectée.Je optimisera ma solution et vous revenir à vous.1 Conseils si ... stockez plutôt que vous stockez le résultat dans une table temporelle intermédiaire avec index créé et essayez-le.


@Francis P, modifié la requête


Désolé peut-être que je n'étais pas clair dans mon explication, mais vous avez mal compris les exigences. 1st: J'ai besoin de 3 groupes d'éléments N, pas n groupes de 3 éléments. 2ème: l'élément ne peut pas être en 2 groupes.


Pouvez-vous fournir une petite quantité de données d'entrée avec la sortie que vous attendez. Ce sera utile.



1
votes

SQL n'est vraiment pas le meilleur outil pour ce type de problème.

Cependant, il est parfois amusant de baster des vis avec le marteau TSQL !! P>

Voici un effort qui obtient les éléments suivants sur vos données d'exemple de 75 lignes: p> xxx pré>

en dessous une seconde sur ma machine.
Juste une mise en garde: cette méthode comporte des défauts massifs, mais si vous avez besoin de le faire dans SQL, vous pouvez probablement gaffer bande sur eux un peu, je n'ai tout simplement pas eu le temps de. P>

-- **Expects data in table t_stats (id, ratio)**
if OBJECT_ID('tempdb..#data') is not null drop table #data
if OBJECT_ID('tempdb..#pairsets') is not null drop table #pairsets
if OBJECT_ID('tempdb..#pairseed') is not null drop table #pairseed
if OBJECT_ID('tempdb..#match') is not null drop proc #match
go

-- rather horrible routine using dsql to find either:
--   1) groups of values that sum to exactly @targetsum (only if @targetsum non null)
--   2) the group containing the least values that includes data id @includeid and where the sum is within +- @targetsumrange
create proc #match(@targetsum DECIMAL(8,4), @includeid int, @targetsumrange DECIMAL(8,4)) as
begin
  set nocount on
  declare @nearestmatch bit = 0
  if @targetsum is null set @nearestmatch = 1
  declare @combination table (value int, asstring varchar(10), alias varchar(50))  
  declare @savedpairseed int = (select pairseed from #pairseed)

  declare @stmtTemplate varchar(max) = 'declare @pairseed int = (select pairseed from #pairseed)
  declare @DistSum DECIMAL(8,4)
  <DeclareVars>
  declare candloop cursor for select <SelectList>, <DistanceSum> as Dist_sum from <TableList> where <IdCheck> <SumCheck>
  open candloop
  fetch next from candloop into <VarsList>, @DistSum
  while @@fetch_status = 0
  begin
    if (select count(*) from #data where id in (<VarsList>)) = <VarsCount>
    begin
      <DeleteData>
      <InsertPairs>
      set @pairseed = @pairseed + 1  
    end
    fetch next from candloop into <VarsList>, @DistSum
  end
  close candloop
  deallocate candloop
  update #pairseed set pairseed = @pairseed  '

  declare @combinations int = 1
  declare @maxcombinations int = 8
  while @combinations <= @maxcombinations
  begin
    insert @combination select @combinations, cast(@combinations as varchar(10)), char(ascii('a') + @combinations-1)
    declare @DeclareVars varchar(max) = ''
    declare @SelectList varchar(max) = ''
    declare @TableList varchar(max) = ''
    declare @IdCheck varchar(max) = ''
    declare @DistanceSum varchar(max) = ''
    declare @InsertPairs varchar(max) = ''
    declare @VarsList varchar(max) = ''
    declare @SumCheck varchar(max) = ''
    declare @DeleteData varchar(max) = 'delete #data where id in (<VarsList>)'

    select @DeclareVars = @DeclareVars + 'declare @id'+asstring+ ' int ' from @combination
    select @SelectList = @SelectList + alias +'.id, ' from @combination
    set @SelectList = SUBSTRING(@selectlist, 1, LEN(@SelectList)-1)
    select @TableList = @TableList + '#data '+alias+', ' from @combination
    set @TableList = SUBSTRING(@TableList, 1, LEN(@TableList)-1)
    select @IdCheck = @IdCheck + a.alias+'.id < '+b.alias+'.id and '
    from @combination a join @combination b on a.value+1 = b.value   
    if LEN(@IdCheck) > 4
      set @IdCheck = SUBSTRING(@IdCheck, 1, LEN(@IdCheck)-4) + ' and '
    select @DistanceSum = @DistanceSum + alias+'.targetdistance + ' from @combination
    set @DistanceSum = SUBSTRING(@DistanceSum, 1, LEN(@DistanceSum)-2)
    select @VarsList = @VarsList + '@id'+asstring+ ', ' from @combination
    set @VarsList = SUBSTRING(@VarsList, 1, LEN(@VarsList)-1)
    select @InsertPairs = @InsertPairs + 'insert #pairsets select @pairseed, @id'+asstring+ ', @DistSum'+ CHAR(10) from @combination
    set @SumCheck = @DistanceSum + ' = '+ cast(@Targetsum as varchar(20))   

    if @nearestmatch = 1 
    begin
      set @SumCheck = '('
      select @SumCheck = @SumCheck + alias+'.id = '+CAST(@includeid as varchar(10))+' or ' from @combination
      if LEN(@SumCheck) > 4
        set @SumCheck = SUBSTRING(@SumCheck, 1, LEN(@SumCheck)-3)
      set @SumCheck = @SumCheck + ')'
      set @DeleteData = ''
    end

    declare @stmt varchar(max)
    set @stmt = REPLACE(@stmtTemplate, '<DeclareVars>', @DeclareVars)
    set @stmt = REPLACE(@stmt, '<DeleteData>', @DeleteData)
    set @stmt = REPLACE(@stmt, '<SelectList>', @SelectList)
    set @stmt = REPLACE(@stmt, '<TableList>', @TableList)
    set @stmt = REPLACE(@stmt, '<IdCheck>', @IdCheck)
    set @stmt = REPLACE(@stmt, '<DistanceSum>', @DistanceSum)
    set @stmt = REPLACE(@stmt, '<InsertPairs>', @InsertPairs)
    set @stmt = REPLACE(@stmt, '<VarsList>', @VarsList)
    set @stmt = REPLACE(@stmt, '<VarsCount>', cast(@combinations as varchar(10)))
    set @stmt = REPLACE(@stmt, '<SumCheck>', @SumCheck)       
    exec (@stmt)    
    set @combinations = @combinations + 1
  end

  if @nearestmatch = 1
  begin
    -- above will have recorded all possible matches within range
    -- remove all but the closest and reindex the pair ids
    declare @bestmatch int
    select top 1 @bestmatch = pairid from #pairsets where pairid >= @savedpairseed and ABS(distsum) < @targetsumrange 
    delete #pairsets where pairid >= @savedpairseed and pairid <> ISNULL(@bestmatch, -1)
    delete #data where id in (select id from #pairsets where pairid = @bestmatch)
    update #pairsets set pairid = @savedpairseed where pairid = @bestmatch
    update #pairseed set pairseed = @savedpairseed+1
  end

end

go
set nocount on
-- set the parameters
declare @xmin DECIMAL(8,4) = 0.75
declare @xmax DECIMAL(8,4) = 0.85
declare @xrange DECIMAL(8,4) = @xmax - @xmin
declare @xtarg DECIMAL(8,4) = (@xmin+@xmax) / 2
declare @ngroups int = 3
declare @targetgroupsize int = 25

declare @maxbalancedpair int 

-- copy the ratio data (using 75 row data from updated question)
select *, ratio-@xtarg as targetdistance, abs(ratio - @xtarg) as targetdistanceabsolute into #data from t_stats
create table #pairseed (pairseed int)
create table #pairsets (pairid int, id int, distsum DECIMAL(8,4) )
insert #pairseed select 1

-- due to the 2 decimal points and distribution of the data we can find many n-tuples that sum to zero
exec #match 0, 0, 0

select @maxbalancedpair = pairseed-1 from #pairseed

declare @deviants table (id int)
declare @most_deviant int
while exists(select * from #data where id not in (select id from @deviants)) 
begin
  select top 1 @most_deviant = id from #data where id not in (select id from @deviants)  order by targetdistanceabsolute desc
  insert @deviants select @most_deviant
  exec #match null, @most_deviant, @xrange
end

-- in general there would have to be some backtracking here
-- now its a box-packing problem, but for simplicity just assign them round robin
declare  @output_group_pairs table (groupid int, pairid int)
declare @groupidx int = 1
declare @numgroups int = 3
declare @pairid int
select @pairid = pairseed-1 from #pairseed

while @pairid >= 0
begin
  insert @output_group_pairs select @groupidx, @pairid
  set @pairid = @pairid - 1
  set @groupidx = (@groupidx % @numgroups) + 1
end

-- wimpy effort at redistributing the groups evenly
-- todo: many cases will not work, should use a proper algorithm

declare @maxiter int = 100
declare @previouspairs table (pairid int)
declare @previousgroups table (groupid int)
while exists(select groupid from @output_group_pairs a join #pairsets b on a.pairid = b.pairid group by groupid having COUNT(id) < @targetgroupsize)
begin  
  set @maxiter = @maxiter-1
  if @maxiter = 0 break
  declare @groupid int = -1
  declare @amountout int
  select @groupid = groupid, @amountout = @targetgroupsize-COUNT(*) 
  from @output_group_pairs a join #pairsets b on a.pairid = b.pairid 
  where groupid not in (select groupid from @previousgroups)
  group by groupid having COUNT(*) < @targetgroupsize
  if @groupid = -1 break

  declare @targetpair int = -1  

  select @targetpair = a.pairid from @output_group_pairs a
  join (select pairid from #pairsets group by pairid having COUNT(*) <= @amountout) b on a.pairid = b.pairid
  join (select groupid, count(id) groupcount from @output_group_pairs a join #pairsets b on a.pairid = b.pairid group by groupid) group_counts on a.groupid = group_counts.groupid
  where a.pairid not in (select pairid from @previouspairs)
  order by abs(@amountout - groupcount) asc

  if @targetpair = -1
  begin
    insert @previousgroups select @groupid
  end
  else
  begin
    insert @previouspairs select @targetpair
    update @output_group_pairs set groupid = @groupid where pairid = @targetpair   
  end
end

set @maxiter = 100
delete @previouspairs
delete @previousgroups
while exists(select groupid from @output_group_pairs a join #pairsets b on a.pairid = b.pairid group by groupid having COUNT(id) > @targetgroupsize)
begin  
  set @maxiter = @maxiter-1
  if @maxiter = 0 break
  set @groupid = -1
  set @amountout = null
  select @groupid = groupid, @amountout = COUNT(*)-@targetgroupsize 
  from @output_group_pairs a join #pairsets b on a.pairid = b.pairid 
  where groupid not in (select groupid from @previousgroups)
  group by groupid having COUNT(*) > @targetgroupsize
  if @groupid = -1 break

  set @targetpair = -1 

  select @targetpair = a.pairid from @output_group_pairs a
  join (select pairid from #pairsets group by pairid having COUNT(*) <= @amountout) b on a.pairid = b.pairid
  join (select groupid, count(id) groupcount from @output_group_pairs a join #pairsets b on a.pairid = b.pairid group by groupid) group_counts on a.groupid = group_counts.groupid
  where a.pairid not in (select pairid from @previouspairs)
  order by abs(@amountout - groupcount) asc

  if @targetpair = -1
  begin
    insert @previousgroups select @groupid
  end
  else
  begin  
    insert @previouspairs select @targetpair
    delete @output_group_pairs where pairid = @targetpair
  end   
end

-- output groups and their stats
select GroupId, Id from @output_group_pairs a join #pairsets b on a.pairid = b.pairid order by 1, 2

select a.GroupId, AVG(c.ratio) as [Average] , count(*) as [Count]
from @output_group_pairs a
join #pairsets b on a.pairid = b.pairid
join t_stats c on b.id = c.id
group by a.groupid
go

drop table #data
drop table #pairsets
drop table #pairseed
drop proc #match


5 commentaires

Merci beaucoup ... je suis impressionné! Comment puis-je modifier votre script afin de spécifier combien d'articles par groupe je veux? (Faites 3 groupes de 20 valeurs à partir des valeurs 75 dans T_STATS )


Une autre chose: vous avez défini @ xmin = 0.75 et @ xmax = 0.85 , qui donne des groupes ayant avg (rapport) environ 0,79 et < Code> Nombre (*) = 25 (parfait). Si je change ces valeurs à @ xmin = 0,78 et @ xmax = 0.80 , je reçois ensuite avg (rapport) = 0,90 et et et et Count (*) = 9672 (c'est un problème).


Oh .. votre exemple était d'obtenir 3 groupes de 30 sur 75 de 75 ans, j'ai donc ignoré l'exigence de «n» d'être variable, mais elle pourrait être ajoutée à la partie de l'emballage de la boîte assez facilement (c'est probablement la pièce avec les principaux problèmes. tel qu'il est). Le bogue qui affecte la caisse de 0,78 à 0,80 est dans les lignes 131 à 137, commencez-les et il s'abstient d'ajouter des ID à plusieurs groupes.


Vous pouvez donc aider à adapter la pièce d'emballage de la boîte à sélectionner «N» éléments?


J'ai mis à jour le code pour créer une simple tentative "gourmande" d'obtenir les groupes à la taille de la cible.



0
votes

oh et si le nombre d'éléments d'un groupe est une exigence précise, voici une version qui utilise la même correspondance exhaustive pour la partie d'emballage de la boîte, c'est beaucoup plus lente cependant.

-- **Expects data in table t_stats (id, ratio)**
if OBJECT_ID('tempdb..#data') is not null drop table #data
if OBJECT_ID('tempdb..#data_pairs') is not null drop table #data_pairs
if OBJECT_ID('tempdb..#pairsets') is not null drop table #pairsets
if OBJECT_ID('tempdb..#pairseed') is not null drop table #pairseed
if OBJECT_ID('tempdb..#match') is not null drop proc #match
go

-- rather horrible routine using dsql to find either:
--   1) groups of values that sum to exactly @targetsum (only if @targetsum non null)
--   2) the group containing the least values that includes data id @includeid and where the sum is within +- @targetsumrange
create proc #match(@targetsum DECIMAL(8,4), @maxcombinations int, @includeid int, @targetsumrange DECIMAL(8,4)) as
begin
  set nocount on
  declare @nearestmatch bit = 0
  if @targetsum is null set @nearestmatch = 1
  declare @combination table (value int, asstring varchar(10), alias varchar(50))  
  declare @savedpairseed int = (select pairseed from #pairseed)

  declare @stmtTemplate varchar(max) = 'declare @pairseed int = (select pairseed from #pairseed)
  declare @DistSum DECIMAL(8,4)
  <DeclareVars>
  declare candloop cursor for select <SelectList>, <DistanceSum> as Dist_sum from <TableList> where <IdCheck> <SumCheck>
  open candloop
  fetch next from candloop into <VarsList>, @DistSum
  while @@fetch_status = 0
  begin
    if (select count(*) from #data where id in (<VarsList>)) = <VarsCount>
    begin
      <DeleteData>
      <InsertPairs>
      set @pairseed = @pairseed + 1  
    end
    fetch next from candloop into <VarsList>, @DistSum
  end
  close candloop
  deallocate candloop
  update #pairseed set pairseed = @pairseed  '

  declare @combinations int = 1
  while @combinations <= @maxcombinations
  begin
    insert @combination 
    select @combinations, cast(@combinations as varchar(10)), CHAR(ASCII('a')+ (@combinations-1)%26) + char(ascii('a') + @combinations-1)
    declare @DeclareVars varchar(max) = ''
    declare @SelectList varchar(max) = ''
    declare @TableList varchar(max) = ''
    declare @IdCheck varchar(max) = ''
    declare @DistanceSum varchar(max) = ''
    declare @InsertPairs varchar(max) = ''
    declare @VarsList varchar(max) = ''
    declare @SumCheck varchar(max) = ''
    declare @DeleteData varchar(max) = 'delete #data where id in (<VarsList>)'

    select @DeclareVars = @DeclareVars + 'declare @id'+asstring+ ' int ' from @combination
    select @SelectList = @SelectList + alias +'.id, ' from @combination
    set @SelectList = SUBSTRING(@selectlist, 1, LEN(@SelectList)-1)
    select @TableList = @TableList + '#data '+alias+', ' from @combination
    set @TableList = SUBSTRING(@TableList, 1, LEN(@TableList)-1)
    select @IdCheck = @IdCheck + a.alias+'.id < '+b.alias+'.id and '
    from @combination a join @combination b on a.value+1 = b.value   
    if LEN(@IdCheck) > 4
      set @IdCheck = SUBSTRING(@IdCheck, 1, LEN(@IdCheck)-4) + ' and '
    select @DistanceSum = @DistanceSum + alias+'.targetdistance + ' from @combination
    set @DistanceSum = SUBSTRING(@DistanceSum, 1, LEN(@DistanceSum)-2)
    select @VarsList = @VarsList + '@id'+asstring+ ', ' from @combination
    set @VarsList = SUBSTRING(@VarsList, 1, LEN(@VarsList)-1)
    select @InsertPairs = @InsertPairs + 'insert #pairsets select @pairseed, @id'+asstring+ ', @DistSum'+ CHAR(10) from @combination
    set @SumCheck = @DistanceSum + ' = '+ cast(@Targetsum as varchar(20))   

    if @nearestmatch = 1 
    begin
      set @SumCheck = '('
      select @SumCheck = @SumCheck + alias+'.id = '+CAST(@includeid as varchar(10))+' or ' from @combination
      if LEN(@SumCheck) > 4
        set @SumCheck = SUBSTRING(@SumCheck, 1, LEN(@SumCheck)-3)
      set @SumCheck = @SumCheck + ')'
      set @DeleteData = ''
    end

    declare @stmt varchar(max)
    set @stmt = REPLACE(@stmtTemplate, '<DeclareVars>', @DeclareVars)
    set @stmt = REPLACE(@stmt, '<DeleteData>', @DeleteData)
    set @stmt = REPLACE(@stmt, '<SelectList>', @SelectList)
    set @stmt = REPLACE(@stmt, '<TableList>', @TableList)
    set @stmt = REPLACE(@stmt, '<IdCheck>', @IdCheck)
    set @stmt = REPLACE(@stmt, '<DistanceSum>', @DistanceSum)
    set @stmt = REPLACE(@stmt, '<InsertPairs>', @InsertPairs)
    set @stmt = REPLACE(@stmt, '<VarsList>', @VarsList)
    set @stmt = REPLACE(@stmt, '<VarsCount>', cast(@combinations as varchar(10)))
    set @stmt = REPLACE(@stmt, '<SumCheck>', @SumCheck) 

    exec (@stmt)    
    set @combinations = @combinations + 1
  end

  if @nearestmatch = 1
  begin
    -- above will have recorded all possible matches within range
    -- remove all but the closest and reindex the pair ids
    declare @bestmatch int
    select top 1 @bestmatch = pairid from #pairsets where pairid >= @savedpairseed and ABS(distsum) < @targetsumrange 
    delete #pairsets where pairid >= @savedpairseed and pairid <> ISNULL(@bestmatch, -1)
    delete #data where id in (select id from #pairsets where pairid = @bestmatch)
    update #pairsets set pairid = @savedpairseed where pairid = @bestmatch
    update #pairseed set pairseed = @savedpairseed+1
  end

end

go
set nocount on
-- set the parameters
declare @xmin DECIMAL(8,4) = 0.75
declare @xmax DECIMAL(8,4) = 0.85
declare @xrange DECIMAL(8,4) = @xmax - @xmin
declare @xtarg DECIMAL(8,4) = (@xmin+@xmax) / 2
declare @ngroups int = 3
declare @targetgroupsize int = 5

declare @maxbalancedpair int 

-- copy the ratio data (using 75 row data from updated question)
select *, ratio-@xtarg as targetdistance, abs(ratio - @xtarg) as targetdistanceabsolute into #data from t_stats
create table #pairseed (pairseed int)
create table #pairsets (pairid int, id int, distsum DECIMAL(8,4) )
insert #pairseed select 1

-- due to the 2 decimal points and distribution of the data we can find many n-tuples that sum to zero
exec #match 0, 8, 0, 0

select @maxbalancedpair = pairseed-1 from #pairseed

declare @deviants table (id int)
declare @most_deviant int
while exists(select * from #data where id not in (select id from @deviants)) 
begin
  select top 1 @most_deviant = id from #data where id not in (select id from @deviants)  order by targetdistanceabsolute desc
  insert @deviants select @most_deviant
  exec #match null, 8, @most_deviant, @xrange
end

select * into #data_pairs from #pairsets
delete #data
delete #pairsets
update #pairseed set pairseed = 1
insert #data
select pairid, COUNT(*), COUNT(*), COUNT(*) from #data_pairs group by pairid

if (select SUM(ratio) from #data) < @targetgroupsize * @ngroups
begin
  raiserror('Cannot match - not enough data', 16, 1)
  return
end

-- find the minimum number of matches that will reach targetgroupsize
declare @maxmatches int = -1
declare @matchcount int
declare @matchsum int = 0
declare maxmatchcount cursor for select CAST(ratio as int) from #data order by ratio asc
open maxmatchcount
fetch next from maxmatchcount into @matchcount
while @@FETCH_STATUS = 0 and @matchsum <= @targetgroupsize
begin
  set @maxmatches = @maxmatches + 1
  set @matchsum = @matchsum + @matchcount
  fetch next from maxmatchcount into @matchcount
end
close maxmatchcount
deallocate maxmatchcount

exec #match @targetgroupsize, @maxmatches, null, null

declare  @output_group_pairs table (groupid int, pairid int)

insert @output_group_pairs select pairid, id from #pairsets where pairid <= @ngroups

-- output groups and their stats
select GroupId, Id from @output_group_pairs a join #data_pairs b on a.pairid = b.pairid order by 1, 2

select a.GroupId, AVG(c.ratio) as [Average] , count(*) as [Count]
from @output_group_pairs a
join #data_pairs b on a.pairid = b.pairid
join t_stats c on b.id = c.id
group by a.groupid

go

drop table #data
drop table #data_pairs
drop table #pairsets
drop table #pairseed
drop proc #match


2 commentaires

Je me demande comment votre code fonctionne ... je l'exécute pour 3 groupes de 25 avec 0.75 et il fonctionne avec final avg (rapport) = 0,79 . Mais si je le change de 3 groupes de 25 éléments, mais 0,7 Il n'est pas capable de trouver une solution. Pourquoi ça?


Dans le pire des cas, il faudra beaucoup de mémoire en raison de la brute forçant les combinaisons. Peut-être devriez-vous exécuter tous les algorithmes suggérés et choisir la meilleure réponse après X secondes ... :)



3
votes

Voici une version procédurale T-SQL qui est quelque peu similaire à un projet , seul le projet de commande est optimisé chaque cycle en fonction de la nécessité.

La nature "compétitive" de cela semble conduire à des ratios légèrement inférieurs à la perfectionner si tous les articles doivent être choisis, mais le contournement est que vous avez essentiellement un O (n ^ 2) algorithme puisqu'il s'agit essentiellement d'une fonction min dans une boucle (peut-être que c'est optimiste en considérant le groupe par clauses). Il est également déterministe et devrait être assez simple à mettre en œuvre dans une autre couche si nécessaire. xxx


1 commentaires

Merci, bien qu'il y ait beaucoup d'espace pour l'optimisation ici. Veuillez nous mettre à jour si vous faites n'importe quoi pour améliorer cela mieux.