ITPub博客

首页 > 数据库 > Oracle > 一个实际问题引发的SQL

一个实际问题引发的SQL

原创 Oracle 作者:kisscactus 时间:2016-03-09 22:28:03 0 删除 编辑
今天一开小厂生产贴膜的同乡告诉我。因为膜较贵,切的时候浪费得有点多,怎么切最省,不想浪费太多。
问题模拟后如下:
问题1:一个长1020的线,要分成132,137,140三个长度的,怎么分最省。可以不分,有哪些方案
问题2:假如我要分39根132长的,88根110长的,60根158长的,怎么分最省。(线的长度还是1020)。--PS,后面这几个值是随机模拟的,

因为之前看了杨长老的海盗分金
http://mp.weixin.qq.com/s?__biz=MjM5MDAxOTk2MQ==&mid=402152545&idx=1&sn=26a5a4d63435b3bfa37f2266cfb89c53&scene=1&srcid=0219WjiWtXW8a3xuf6YM6vH6&from=singlemessage&isappinstalled=0#wechat_redirect也想模仿试试。思路参考上边连接

问题1
1.比较土的方式,但可以实现问题1
WITH TOT132 AS
 (SELECT (9 - LEVEL) * 132 USED1,
         (9 - LEVEL) USED_NUM1
    FROM DUAL
  CONNECT BY LEVEL <= 9),
TOT137 AS
 (SELECT (9 - LEVEL) * 137 USED2, 9 - LEVEL USED_NUM2
    FROM DUAL
  CONNECT BY  LEVEL <= 9),
TOT140 AS
 (SELECT (9 - LEVEL) * 140 USED3, 9 - LEVEL USED_NUM3
    FROM DUAL
  CONNECT BY  LEVEL <= 9)
SELECT DECODE(USED1,0,132,(USED1)/USED_NUM1) 规格1,
       USED_NUM1 使用张数1,
       DECODE(USED2,0,137,(USED2)/USED_NUM2)  规格2,
       USED_NUM2 使用张数2,
       DECODE(USED3,0,140,(USED3)/USED_NUM3) 规格3,
       USED_NUM3 使用张数3,
       1020 总大小,
       USED1 + USED2 + USED3 用掉的,
       1020 - (USED1 + USED2 + USED3) 浪费掉的
  FROM TOT132, TOT137, TOT140
 WHERE TOT132.USED1 + TOT137.USED2 + TOT140.USED3 <= 1020
   AND TOT132.USED1 >= 0
   AND TOT137.USED2 >= 0
   AND TOT140.USED3 >= 0
 ORDER BY 1020 - (USED1 + USED2 + USED3) ASC
---------------------------------------结果展示,个人理解为穷举..------------------------------------------------------



后面请求了一位大师,下图中的语句为大师提供


简单快捷,显然140长度的分7根最省。因为怎么分,都只能分七根,显然按最大的分最省。。。



 

问题2来了。

---把一根切成132,110,158的方式有131种。方式问1

SELECT N132,N110,N158, (1020 - L132 - L110 - L158) LF
  FROM (SELECT 1020 - 132 * (ROWNUM - 1) LF1,
               132 * (ROWNUM - 1) L132,
               ROWNUM - 1 N132
          FROM DUAL
        CONNECT BY 132 * (ROWNUM - 1) < 1020) A1,
       (SELECT 1020 - 110 * (ROWNUM - 1) LF2,
               110 * (ROWNUM - 1) L110,
               ROWNUM - 1 N110
          FROM DUAL
        CONNECT BY 110 * (ROWNUM - 1) < 1020) A2,
       (SELECT 1020 - 158 * (ROWNUM - 1) LF3,
               158 * (ROWNUM - 1) L158,
               ROWNUM - 1 N158
          FROM DUAL
        CONNECT BY 158 * (ROWNUM - 1) < 1020) A3
 WHERE 1020 - L132 - L110 - L158 >= 0
 ORDER BY LF1 + LF2 + LF3 ASC;




上面查询产生131条记录,知一根线的分割方式有131种后,可以用如下方式(类似穷举)。
SELECT A1.*, A2.*, A3.*, LF1 + LF2 + LF3 TOT_NF, CNT1 + CNT2 + CNT3 CNT
  FROM (WITH TMP1 AS (SELECT 1020 - 132 * (ROWNUM - 1) LF1,
                             132 * (ROWNUM - 1) L132,
                             ROWNUM - 1 N132
                        FROM DUAL
                      CONNECT BY 132 * (ROWNUM - 1) <=1020)
         SELECT *
           FROM TMP1, (SELECT ROWNUM CNT1 FROM DUAL CONNECT BY LEVEL <= 131)) A1,(WITH TMP2 AS (SELECT 1020 -
                                                                                                       110 *
                                                                                                       (ROWNUM - 1) LF2,
                                                                                                       110 *
                                                                                                       (ROWNUM - 1) L110,
                                                                                                       ROWNUM - 1 N110
                                                                                                  FROM DUAL
                                                                                                CONNECT BY 110 *
                                                                                                           (ROWNUM - 1) <=1020)
         SELECT *
           FROM TMP2, (SELECT ROWNUM CNT2 FROM DUAL CONNECT BY LEVEL <= 131)) A2,(WITH TMP3 AS (SELECT 1020 -
                                                                                                       158 *
                                                                                                       (ROWNUM - 1) LF3,
                                                                                                       158 *
                                                                                                       (ROWNUM - 1) L158,
                                                                                                       ROWNUM - 1 N158
                                                                                                  FROM DUAL
                                                                                                CONNECT BY 158 *
                                                                                                           (ROWNUM - 1) <=1020)
         SELECT *
           FROM TMP3, (SELECT ROWNUM CNT3 FROM DUAL CONNECT BY LEVEL <= 131)) A3
         
          WHERE CNT1 * N132 >= 39
            AND CNT2 * N110 >= 88
            AND CNT3 * N158 >= 50
             AND CNT1 * N132 <= 39 +26
            AND CNT2 * N110 <= 88 +11
            AND CNT3 * N158 <= 50 +7
          ORDER BY CNT1 + CNT2 + CNT3 ASC;
加相应的数只是为了限制排序临时表空间不够,加的数量是一根长线能分对应短线的数量限制。
25根可以达到分132长的6*7=42根,110长的90根,158长的54根。且只有一种分法,浪费198长度。

--分39根132长的,88根110长的,60根158长的。25根线可以搞定。现在问题到25根1020的线怎么分39根132长的,88根110长的,60根158长的。
实在想不出来了,又类似前面的方式,搞了一次,结果是出来了,但过程略2,估计有简单的办法。
建立YYS2视图如下:
WITH TOT132 AS (SELECT (9 - LEVEL) * 132 USED1, (9 - LEVEL) USED_NUM1
                          FROM DUAL
                        CONNECT BY LEVEL <= 9), TOT110 AS (SELECT (11 - LEVEL) * 110 USED2,
                                                                  11 - LEVEL USED_NUM2
                                                             FROM DUAL
                                                           CONNECT BY LEVEL <= 11), TOT158 AS (SELECT (8 -
                                                                                                     LEVEL) * 158 USED3,
                                                                                                     8 -
                                                                                                     LEVEL USED_NUM3
                                                                                                FROM DUAL
                                                                                              CONNECT BY LEVEL <= 8)
         SELECT '方案' || ROWNUM 方案,
                DECODE(USED1, 0, 132, (USED1) / USED_NUM1) 规格1,
                USED_NUM1 使用张数1,
                DECODE(USED2, 0, 110, (USED2) / USED_NUM2) 规格2,
                USED_NUM2 使用张数2,
                DECODE(USED3, 0, 158, (USED3) / USED_NUM3) 规格3,
                USED_NUM3 使用张数3,
                1020 总大小,
                USED1 + USED2 + USED3 用掉的,
                1020 - (USED1 + USED2 + USED3) 浪费掉的
           FROM TOT132, TOT110, TOT158
          WHERE TOT132.USED1 + TOT110.USED2 + TOT158.USED3 <= 1020
            AND TOT132.USED1 >= 0
            AND TOT110.USED2 >= 0
            AND TOT158.USED3 >= 0
          ORDER BY 1020 - (USED1 + USED2 + USED3) ASC;

参考上面的方式,执行如下查询:
SELECT A1.*,
       A2.*,
       A3.*,
       A1.使用张数1 * A1.CNT + A2.使用张数1 * A2.CNT + A3.使用张数1 * A3.CNT TOT1,
       A1.使用张数2 * A1.CNT + A2.使用张数2 * A2.CNT + A3.使用张数2 * A3.CNT TOT2,
       A1.使用张数3 * A1.CNT + A2.使用张数3 * A2.CNT + A3.使用张数3 * A3.CNT TOT3,
       A1.CNT + A2.CNT + A3.CNT TOT_P,
       A1.CNT * A1.浪费掉的 + A2.CNT * A2.浪费掉的 + A3.CNT * A3.浪费掉的 TOT_LF
  FROM (SELECT 方案,
               规格1,
               使用张数1,
               规格2,
               使用张数2,
               规格3,
               使用张数3,
               总大小,
               用掉的,
               浪费掉的,
               CNT
          FROM (SELECT (26 - LEVEL) CNT, LEVEL LV
                  FROM DUAL
                CONNECT BY LEVEL <= 26) A,
               YYS2) A1,
       (SELECT 方案,
               规格1,
               使用张数1,
               规格2,
               使用张数2,
               规格3,
               使用张数3,
               总大小,
               用掉的,
               浪费掉的,
               CNT
          FROM (SELECT (26 - LEVEL) CNT, LEVEL LV
                  FROM DUAL
                CONNECT BY LEVEL <= 26) A,
               YYS2) A2,
       (SELECT 方案,
               规格1,
               使用张数1,
               规格2,
               使用张数2,
               规格3,
               使用张数3,
               总大小,
               用掉的,
               浪费掉的,
               CNT
          FROM (SELECT (26 - LEVEL) CNT, LEVEL LV
                  FROM DUAL
                CONNECT BY LEVEL <= 26) A,
               YYS2) A3
 WHERE A1.CNT + A2.CNT + A3.CNT = 25
   AND A1.使用张数1 * A1.CNT + A2.使用张数1 * A2.CNT + A3.使用张数1 * A3.CNT >= 39
   AND A1.使用张数2 * A1.CNT + A2.使用张数2 * A2.CNT + A3.使用张数2 * A3.CNT >= 88
   AND A1.使用张数3 * A1.CNT + A2.使用张数3 * A2.CNT + A3.使用张数3 * A3.CNT >= 60
  AND A1.使用张数1 * A1.CNT + A2.使用张数1 * A2.CNT + A3.使用张数1 * A3.CNT <= 39 + 26
   AND A1.使用张数2 * A1.CNT + A2.使用张数2 * A2.CNT + A3.使用张数2 * A3.CNT <= 88 + 11
   AND A1.使用张数3 * A1.CNT + A2.使用张数3 * A2.CNT + A3.使用张数3 * A3.CNT <= 60 + 17
 ORDER BY -1 ASC
加相应的数只是为了限制排序临时表空间不够,加的数量是一根长线能分对应短线的数量限制。
最结结果出来了,不过和上面有点对不上。选的列太多,不好截图,用excel展示下好了。
    方案 规格1 使用张数1 规格2 使用张数2 规格3 使用张数3 总大小 用掉的 浪费掉的 CNT 方案 规格1 使用张数1 规格2 使用张数2 规格3 使用张数3 总大小 用掉的 浪费掉的 CNT 方案 规格1 使用张数1 规格2 使用张数2 规格3 使用张数3 总大小 用掉的 浪费掉的 CNT TOT1 TOT2 TOT3 TOT_P TOT_LF
1 方案44 132 2 110 4 158 2 1020 1020 0 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
2 方案14 132 4 110 3 158 1 1020 1016 4 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
3 方案64 132 1 110 8 158 0 1020 1012 8 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
4 方案2 132 6 110 2 158 0 1020 1012 8 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
5 方案113 132 0 110 2 158 5 1020 1010 10 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
6 方案54 132 2 110 1 158 4 1020 1006 14 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
7 方案21 132 4 110 0 158 3 1020 1002 18 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
8 方案68 132 1 110 5 158 2 1020 998 22 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
9 方案26 132 3 110 4 158 1 1020 994 26 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
10 方案6 132 5 110 3 158 0 1020 990 30 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
11 方案94 132 0 110 9 158 0 1020 990 30 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
12 方案78 132 1 110 2 158 4 1020 984 36 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
13 方案33 132 3 110 1 158 3 1020 980 40 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
14 方案10 132 5 110 0 158 2 1020 976 44 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
15 方案98 132 0 110 6 158 2 1020 976 44 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
16 方案42 132 2 110 5 158 1 1020 972 48 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
17 方案13 132 4 110 4 158 0 1020 968 52 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
18 方案108 132 0 110 3 158 4 1020 962 58 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216
19 方案50 132 2 110 2 158 3 1020 958 62 0 方案125 132 0 110 0 158 6 1020 948 72 3 方案44 132 2 110 4 158 2 1020 1020 0 22 44 88 62 25 216

如上图第一行(具体方案参考上面一个视图YYS)--太宽了,后面的展示不出来。一行有三个小方案的,编辑的时候可以看到:
实施步骤:
1.方案125用3次。方案125把1020全切为158的6根,每一根用掉948,浪费72.一共浪费216,产生18根158的
2.方案44用22(上面表格每一行展示了三组小方案,一行为一个大方案,前面也是方案44,但没有,根据展示结果,用后面一组。)次。方案44把1020分成2根132的,,4根110的,2根158的。不浪费.产生44根132的,88根110的,44根158的
综合步骤1、2. 产生132的,110的,158的分别为44,88,60根。
回到题目2:假如我要分39根132长的,88根110长的,60根158长的,怎么分最省。(线的长度还是1020)

能达到要求。但过程太绕.
不过这完全没有什么道理,其实切割的时候可以选N种方案,并不是选三种每种方案执行几次。



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/27349469/viewspace-2052623/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-12-29

  • 博文量
    12
  • 访问量
    27111