【问题标题】:Oracle randomly shuffling entire rowsOracle 随机打乱整行
【发布时间】:2020-10-11 09:11:02
【问题描述】:

有一个包含 3 种记录类型的位置表(见下文)。我只需要 SELECT record_type = 'G' 行。

我想将数据包装在一个循环中(即 5 次),但是如何通过 location_id 随机打乱整个行,以便它们在循环的每次迭代中以不同的顺序出现?也许,将行粘贴到一个数组中并打乱数组?

注意,我不想打乱列,我希望行保持完整。未来可能会增加更多地点。

CREATE TABLE locations AS
SELECT level AS location_id,
       'Door ' || level AS location_name,

CASE round(dbms_random.value(1,3)) 
            WHEN 1 THEN 'A' 
            WHEN 2 THEN 'T' 
            WHEN 3 THEN 'G' 
         END AS location_type

FROM   dual
CONNECT BY level <= 25;

SELECT * from tour_detail 
Order by tour_id, tour_time

TOUR_ID TOUR_TIME    LOCATION_ID
1   06212020 00:10:25   2
1   06212020 00:21:05   18
1   06212020 00:30:33   11
1   06212020 00:40:51   17
1   06212020 00:52:13   4
1   06212020 01:01:42   2
1   06212020 01:07:52   11

我们有一个门禁系统,当您滑动卡片时,它会以 MMDDYYY HH24:MI:SS 格式记录 card_num、location_id、access_date。

有些人想创建一个巡视系统。这会将 access_date 与 tour_detail 详细信息日期进行比较。如果在某个标准内说 + 或 - 2 分钟,这意味着守卫准时,如果 GT 或 LT 2 分钟,我们记录早或晚,如果 GT 或 LT 5 分钟或没有 access_history 记录,我们记录未出现。

我被要求汇总一些测试数据。如您所见,tour_detail 记录包含 MMDDYYYY HH24:MI:SS,所以我正在考虑将 tour_detail 记录更改为间隔小时到分钟,但我对此几乎没有经验。

【问题讨论】:

  • “随机洗牌”和“循环的每次迭代以不同的顺序”不能同时实现。通过随机洗牌,您可以获得两次或多次相同的订单。您想遍历所有可能的订单组合一次吗?还是您只是想要每次随机排序?
  • 不,我只想随机播放,不需要每个组合都不同。我想要这个 怎么能这样做: BEGIN FOR l_counter IN 1..5 LOOP For 1 to each location.count Loop Print location_id End loop 随机打乱位置表中的所有记录 END LOOP;结束;

标签: sql arrays oracle shuffle


【解决方案1】:

所以它们在循环的每次迭代中以不同的顺序出现

这是没有意义的。您正在向表中插入行。行(在 RDBMS 表中)不存储以任何特定顺序。

但是,您可以在从该表中选择时对它们进行排序,并且 - 为了做到这一点 - 您必须使用 order by 子句。


在选择时,看看这是否有帮助:

SQL> with data as
  2    (select empno, ename, job, sal
  3     from emp
  4     where deptno = 20
  5     order by round(dbms_random.value(0, 15))
  6    )
  7  select column_value, d.*
  8  from data d cross join table(cast(multiset(select level from dual
  9                                             connect by level <= 5
 10                                            ) as sys.odcinumberlist));

COLUMN_VALUE      EMPNO ENAME      JOB              SAL
------------ ---------- ---------- --------- ----------
           4       7902 FORD       ANALYST         3000
           4       7788 SCOTT      ANALYST         3000
           2       7369 SMITH      CLERK           1000
           4       7369 SMITH      CLERK           1000
           1       7369 SMITH      CLERK           1000
           5       7566 JONES      MANAGER         2975
           1       7876 ADAMS      CLERK           1100
           1       7788 SCOTT      ANALYST         3000
           5       7788 SCOTT      ANALYST         3000
           3       7876 ADAMS      CLERK           1100
           1       7902 FORD       ANALYST         3000
           2       7876 ADAMS      CLERK           1100
           5       7902 FORD       ANALYST         3000
           3       7902 FORD       ANALYST         3000
           3       7566 JONES      MANAGER         2975
           1       7566 JONES      MANAGER         2975
           3       7788 SCOTT      ANALYST         3000
           2       7902 FORD       ANALYST         3000
           4       7566 JONES      MANAGER         2975
           5       7876 ADAMS      CLERK           1100
           2       7788 SCOTT      ANALYST         3000
           3       7369 SMITH      CLERK           1000
           4       7876 ADAMS      CLERK           1100
           2       7566 JONES      MANAGER         2975
           5       7369 SMITH      CLERK           1000

25 rows selected.

SQL>

【讨论】:

  • 我想这样做 BEGIN FOR l_counter IN 1..5 LOOP For 1 to each location.count Loop Print location_id End loop 随机打乱位置表中的所有记录 END LOOP;结束;
  • 我编辑了我的答案并添加了一个示例;请看一下。
  • 帮助很大。只是几个问题。 column_value 来自哪里?我可以在 cte 之外添加一列,例如 sysdate+random.value。最后,我可以有一个名为 t1 的表并将其添加到 cte,因为我的目标是从 2 个不同的表和一个 sysdate 值生成数据并将它们插入到一个新表中。感谢您的耐心和专业知识。对于某些人来说,我使用 PLSQL 比使用 Sql 更好
  • 另外,我看到你问了很多问题,但从未接受过你得到的任何答案。为什么?你知道你以这种方式不鼓励未来对你的问题的回答吗?人们不知道他们为帮助你付出的努力是否真的有帮助。
  • 没问题,只是说。至于“当有人回答我的问题时我应该怎么做”,请阅读:stackoverflow.com/help/someone-answers
【解决方案2】:

假设你有一张桌子,里面有 5 个IDs

create table tab as
select rownum id from dual connect by level <= 5;

这会产生随机顺序输出行

select * from tab order by dbms_random.value;

        ID
----------
         2
         4
         5
         1
         3

如果您重复该语句,您会得到不同的(随机)结果

        ID
----------
         5
         4
         2
         1
         3 

如此简单地在循环中重复查询或进行类似的操作

with data as (
select 1 pass_id, id  from tab  
union all
select 2 pass_id, id  from tab  
union all
select 3 pass_id, id  from tab )
select * from data
order by 1,dbms_random.value

【讨论】:

  • 我想这样做: BEGIN FOR l_counter IN 1..5 LOOP For 1 to each location.count Loop Print location_id End loop 随机打乱位置表中的所有记录 END LOOP;结束;
  • @Beefstu 提供带有小数据的预期输出(比如 5 location_id) - 抱歉,对于我想要 shuffle 输出的内容,我仍然不够清楚。
  • @Beefstu - 为什么你如此热衷于使用 for 循环?该解决方案使用游标,其中 --- 根据定义 --- 在你得到它们之前,这些行已经“排序”了。使用别人提供的简单sql有什么问题?如果您需要对以随机顺序返回的行进行一些游标循环处理,那么您将需要基于这些 sql 解决方案之一的显式游标。但我强烈怀疑我们真的在这里处理“x-y 问题”。
  • 我没有嫁给 for 循环,因为我不是开发人员,所以这似乎是完成任务的最简单方法。谢谢你的建议。我会研究游标。
  • @bomber 我用更多细节编辑了原始问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-30
  • 1970-01-01
  • 1970-01-01
  • 2018-11-06
相关资源
最近更新 更多