Advertisement
Guest User

Untitled

a guest
Jan 17th, 2013
147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
MySQL 6.32 KB | None | 0 0
  1. drop table if exists combiner;
  2. create table combiner (owner integer, attribute varchar(16), value varchar(16));
  3.  
  4. insert into combiner values
  5. ('10','COLOR','BLUE'),
  6. ('10','COLOR','RED'),
  7. ('10','COLOR','GREEN'),
  8. ('10','SIZE','BIG'),
  9. ('20','COLOR','GREEN'),
  10. ('20','SIZE','MEDIUM'),
  11. ('20','MEMORY','16G'),
  12. ('20','MEMORY','32G'),
  13. ('30','COLOR','RED'),
  14. ('30','COLOR','BLUE'),
  15. ('30','MEMORY','64G'),
  16. ('40','COLOR','BLUE'),
  17. ('40','COLOR','RED'),
  18. ('40','COLOR','GREEN'),
  19. ('40','SIZE','BIG'),
  20. ('40','SIZE','MEDIUM'),
  21. ('40','MEMORY','16G'),
  22. ('40','MEMORY','32G'),
  23. ('40','CPU','FAST')
  24. ;
  25.  
  26. -- selects the number of possible combinations for an owner
  27. SELECT
  28.     EXP(SUM(LOG(COALESCE(cnt)))) -- calculates number of different combinations for attributes
  29. FROM
  30.     (SELECT attribute, COUNT(*) AS cnt FROM combiner
  31.         WHERE owner = 10  -- for testing
  32.     GROUP BY
  33.         attribute
  34.     ) q1
  35. ;
  36.  
  37. -- we want to operate on thoose numbers from 1..max
  38. -- it would be easy with a stored procedure, but can also be done in purely SQL
  39. -- please note, that I would never use this code in production
  40.  
  41. -- to create this counter, the idea is that n < COUNT(combiner)^2
  42. -- so: create a cross join, and an iterator... for a fixed N:
  43.  
  44. SET @rank=0;
  45. SELECT
  46.     @rank:=@rank+1 AS rank
  47. FROM
  48.     combiner c1,
  49.     combiner c2
  50. WHERE @rank < 5; -- 5 is N
  51.  
  52. -- So combine theese two, to create a loop from 1..N:
  53. -- also note: we need N*M rows, where N is the number of combinations,
  54. -- and M is the number of attributes. So combine!
  55.  
  56. SET @rank=0;
  57. SELECT
  58.     @rank:=@rank+1 AS rank
  59. FROM
  60.     combiner c1,
  61.     combiner c2
  62. WHERE @rank+1 < (
  63.     SELECT
  64.         (
  65.             EXP(SUM(LOG(COALESCE(cnt))))
  66.             * ( SELECT COUNT(DISTINCT attribute) FROM combiner q1 WHERE owner = 10 )  -- number of attributes, fixed 10 is for testing
  67.         )
  68.     FROM
  69.         (SELECT
  70.             attribute,
  71.             COUNT(*) AS cnt        
  72.             FROM combiner c3
  73.             WHERE owner = 10  -- for testing
  74.         GROUP BY
  75.             attribute
  76.         ) q2
  77.     )
  78. ;
  79.  
  80. -- now we have the correct amount of rows, the only thing left is to select the wanted rows...
  81. -- to do that, we need to convert our number back to some row information
  82.  
  83. -- first, the attribute name:
  84. -- we have a number N. for every N, N % attribute_count is the attribute we want to display.
  85. -- which would be easy to select if we could write a custom expression to offset, but we can't.
  86. -- also, we may only define variables at the start of our query, not in beetween - because of this,
  87. -- it is hard to reset a variable inside a query.
  88. -- but not inpossible. For example, see the following simple demonsration:
  89.  
  90. SET @example = 15;
  91. SELECT
  92.     @example, owner
  93. FROM
  94.     combiner
  95. WHERE
  96.     @example := (@example := 0)
  97. UNION
  98. SELECT @example := @example + 1, owner
  99. FROM combiner
  100. ;
  101.  
  102. -- so, to select the Nth attribute, use:
  103.  
  104. SET @attribute_counter = 0;
  105. SELECT attribute
  106.     FROM
  107.     (
  108.         SELECT
  109.             @attribute_counter AS attribute_counter, attribute
  110.         FROM
  111.             combiner
  112.         WHERE
  113.             @attribute_counter := (@attribute_counter := 0)
  114.         UNION
  115.         SELECT @attribute_counter  := @attribute_counter  + 1, attribute
  116.         FROM (
  117.             SELECT DISTINCT attribute
  118.             FROM combiner
  119.             WHERE owner = 10  -- for testing
  120.             ORDER BY attribute) q3
  121.  
  122.     ) q4
  123. WHERE attribute_counter = 2 -- in this example, N = 2
  124. ;
  125.  
  126. -- now combine our counter query and this attribute selector, to solve part of the problem
  127.  
  128. SET @rank=0, @attribute_counter = 0;
  129. SELECT
  130.     @rank AS rank,
  131.     (SELECT COUNT(DISTINCT attribute) FROM combiner WHERE owner = 10 ORDER BY attribute) AS attribute_count,
  132.  
  133.     (SELECT attribute
  134.         FROM
  135.         (
  136.             SELECT
  137.                 @attribute_counter AS attribute_counter, attribute
  138.             FROM
  139.                 combiner
  140.             WHERE
  141.                 @attribute_counter := (@attribute_counter := 0 )
  142.             UNION
  143.             SELECT @attribute_counter  := @attribute_counter  + 1, attribute
  144.             FROM (SELECT DISTINCT attribute FROM combiner WHERE owner = 10 ORDER BY attribute) q3
  145.  
  146.         ) q4
  147.     WHERE attribute_counter = MOD(
  148.         rank,
  149.         attribute_count
  150.         ) + 1
  151.     ) attribute,
  152.  
  153.  
  154.     @rank := @rank + 1 AS rank2
  155. FROM
  156.     combiner c1,
  157.     combiner c2
  158. WHERE @rank+1 < (
  159.     SELECT
  160.         (
  161.             EXP(SUM(LOG(COALESCE(cnt))))
  162.             * ( SELECT COUNT(DISTINCT attribute) FROM combiner q1 WHERE owner = 10 )  -- number of attributes, fixed 10 is for testing
  163.         )
  164.     FROM
  165.         (SELECT
  166.             attribute,
  167.             COUNT(*) AS cnt        
  168.             FROM combiner c3
  169.             WHERE owner = 10  -- for testing
  170.         GROUP BY
  171.             attribute
  172.         ) q2
  173.     )
  174. ;
  175.  
  176. -- the value of the attribute, that's also can be calculated, but it's harder
  177. -- we are in the Nth iteration
  178. -- and at the moment processing the attribute_number attribute
  179. -- there are attribute_count attributes
  180. -- we have completed completed_count attributes
  181. -- also, the attributes AFTER the current have Vx possible values combined
  182. -- which means, this attribute will change in every Vx row
  183. -- and this attribute has Y possible values, let Vy = Vx * Y
  184. -- which is basically Vx INCLUDING this column
  185. -- so N % V gives us a great number to use.
  186.  
  187. -- First: let's compute V based on our previous attribute selector query.
  188.  
  189.  
  190. SET @after_counter = 0;
  191. SELECT
  192.     EXP(SUM(LOG(COALESCE(value_count)))) AS after_rows
  193. FROM
  194.     (
  195.     SELECT
  196.         DISTINCT
  197.         attribute,
  198.         (SELECT COUNT(value) FROM combiner c2 WHERE owner = 10 AND c1.attribute = c2.attribute) value_count
  199.     FROM combiner c1
  200.     WHERE attribute IN
  201.         (
  202.             SELECT attribute
  203.                 FROM
  204.                 (
  205.                     SELECT
  206.                         @after_counter AS after_counter, attribute
  207.                     FROM
  208.                         combiner
  209.                     WHERE
  210.                         @after_counter := (@after_counter := 0)
  211.                     UNION
  212.                     SELECT @after_counter  := @after_counter  + 1, attribute
  213.                     FROM (
  214.                         SELECT DISTINCT attribute
  215.                         FROM combiner
  216.                         WHERE owner = 10  -- for testing
  217.                         ORDER BY attribute
  218.                          ) q5
  219.  
  220.                 ) q6
  221.             WHERE after_counter > 1
  222.         )
  223.     ) q7
  224.     ;
  225.  
  226. -- for owner = 10 in the example
  227. -- for after_counter = 0, it returns 3. But there is no field zero
  228. -- for 1, it retuns 1, since color changes every time
  229. -- for 2, it retuns 0: there is just one size, it never changes
  230. -- for an advanced case, see for my owner = 40 example, which has 4 attributes, with a single-value one inside
  231.  
  232. -- next step: we want value N % V from the attribute. It's easy, using the same way as for the attributes
  233. -- and now we know both N and V, so just combine...
  234.  
  235. -- and final step: refactor the entire query, to run for every owner instead of this fixed example
  236. -- it will be a lot more uglier and larger, but it will run
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement