We have written a MySQL function for our open source ad server AdServerBeans MyAds (http://www.adserverbeans.com) that selects a banner randomly taking into account traffic shares:
DELIMITER ;;
DROP FUNCTION if exists get_random_banner_by_traffic_share;
CREATE FUNCTION get_random_banner_by_traffic_share(valid_banners TEXT, total_traffic_share INTEGER)
RETURNS INTEGER
NOT DETERMINISTIC
BEGIN
DECLARE pos INTEGER DEFAULT 1;
DECLARE rnd INTEGER DEFAULT 0;
DECLARE current_traffic_share INTEGER DEFAULT 0;
DECLARE banner_id INTEGER;
DECLARE banner_traffic_share INTEGER;
SET rnd = RAND()*(total_traffic_share-1)+1;
WHILE pos < LENGTH(valid_banners) DO
SET pos = POSITION(';' IN valid_banners);
SET banner_id = CONVERT(SUBSTR(valid_banners,1,pos-1),SIGNED);
SET valid_banners=SUBSTRING(valid_banners FROM pos+1);
SET pos = POSITION(';' IN valid_banners);
SET banner_traffic_share = CONVERT(SUBSTR(valid_banners,1,pos-1),SIGNED);
SET valid_banners=SUBSTRING(valid_banners FROM pos+1);
if(current_traffic_share < rnd and rnd <= (banner_traffic_share+current_traffic_share)) THEN
RETURN banner_id;
END IF;
SET current_traffic_share=current_traffic_share+banner_traffic_share;
END WHILE;
END;
;;
delimiter ;
MySQL stored procedures/functions do not support arrays/lists. So we had to use a string with delimiters.
In this function pay attention to the line:
SET rnd = RAND()*(total_traffic_share-1)+1;
that randomly selects a value from 1 to 100.
We then look for the banner that lies within that range.
Please note that this algorithm is probably ok for a small amount of ads targeting the same ad place. You might have a different story.