sql技巧

这样的列表确实有用-它们不仅吸引了人们的注意,如果内容也很有价值(在这种情况下,请相信我),则文章格式可能会非常有趣。

本文将为您带来10条SQL技巧,其中许多人可能都认为不可能。 这篇文章是我在会议上(最近在JAX和Devoxx France )发表的,新的,快节奏的,可笑的幼稚幽默的演讲的摘要。 您可以在此引用我:

添加到我的可笑快节奏SQL谈话最后一刻幻灯片@JAXconf ,谈你一定不能错过#Microservices pic.twitter.com/leHuxuolK6

— Lukas Eder(@lukaseder) 2016年4月20日

完整的幻灯片可以在slideshare上看到:

Lukas Eder 认为10种您认为不可能SQL技巧

…而且我敢肯定很快会有录像带。 这是您认为不可能的10条SQL技巧

介绍

为了理解这10种SQL技巧的价值,首先重要的是理解SQL语言的上下文。 为什么在Java会议上谈论SQL? (而且我通常是唯一的一个!)这就是为什么:

从早期开始,编程语言设计人员就有了设计语言的愿望,在这些语言中,您告诉机器结果是什么,而不是如何获得。 例如,在SQL中,您告诉机器您要“连接”(JOIN)用户表和地址表,并找到居住在瑞士的用户。 您无需担心数据库将如何检索此信息(例如,应先加载用户表还是地址表?将这两个表以嵌套循环或哈希表的形式联接吗?是否应先将所有数据加载到内存中?然后针对瑞士用户进行过滤,还是我们应该首先加载瑞士地址?

与每个抽象一样,您仍然需要了解数据库幕后工作的基础知识,以帮助数据库在查询时做出正确的决定。 例如,有意义的是:

  • 在表之间建立正式的外键关系(这告诉数据库,确保每个地址都有对应的用户)
  • 在搜索字段上添加索引:国家(这告诉数据库可以在O(log N)而不是O(N)找到特定的国家)

但是,一旦数据库和应用程序成熟,就可以将所有重要的元数据放置到位,并且您可以只关注业务逻辑。 以下10个技巧展示了仅用几行声明性SQL编写的惊人功能,从而产生简单且复杂的输出。

1.一切都是一张桌子

这是最琐碎的技巧,甚至不是真正的技巧,但这是全面理解SQL的基础: 一切都是表格 ! 当您看到这样SQL语句时:

SELECT *
FROM person

…您将在FROM子句中快速找到坐在那里的表person 。 太酷了,那一张桌子。 但是您是否意识到整个语句也是一个表? 例如,您可以编写:

SELECT *
FROM (SELECT *FROM person
) t

现在,您已经创建了所谓的“派生表”,即FROM子句中的嵌套SELECT语句。

这是微不足道的,但是如果您考虑一下,那将非常优雅。 您还可以使用VALUES()构造函数在某些数据库(例如PostgreSQL,SQL Server)中创建临时内存表:

SELECT *
FROM (VALUES(1),(2),(3)
) t(a)

它简单地产生:

a
---123

如果不支持该子句,则可以还原到派生表,例如在Oracle中:

SELECT *
FROM (SELECT 1 AS a FROM DUAL UNION ALLSELECT 2 AS a FROM DUAL UNION ALLSELECT 3 AS a FROM DUAL
) t

现在您已经看到VALUES()和派生表实际上是同一回事,从概念上讲,让我们回顾一下INSERT语句,它有两种形式:

-- SQL Server, PostgreSQL, some others:
INSERT INTO my_table(a)
VALUES(1),(2),(3);-- Oracle, many others:
INSERT INTO my_table(a)
SELECT 1 AS a FROM DUAL UNION ALL
SELECT 2 AS a FROM DUAL UNION ALL
SELECT 3 AS a FROM DUAL

在SQL中,所有内容都是一个表。 当您向表中插入行时,您实际上并不是在插入单个行。 您实际上是在插入整个表。 大多数人大多数时间只是偶然插入一个单行表,因此没有意识到INSERT真正作用。

一切都是一张桌子。 在PostgreSQL中,甚至函数都是表:

SELECT *
FROM substring('abcde', 2, 3)

以上收益:

substring
---------
bcd

如果您使用Java进行编程,则可以使用Java 8 Stream API的类比将这一步骤更进一步。 考虑以下等效概念:

TABLE          : Stream<Tuple<..>>
SELECT         : map()
DISTINCT       : distinct()
JOIN           : flatMap()
WHERE / HAVING : filter()
GROUP BY       : collect()
ORDER BY       : sorted()
UNION ALL      : concat()

在Java 8中,“一切都是流”(至少在开始使用Stream时)。 无论您如何转换流,例如使用map()filter() ,生成的类型始终都是Stream。

我们写了整篇文章来对此进行更深入的解释,并将Stream API与SQL进行比较: Java 8 Streams中的常见SQL子句及其等效项

而且,如果您正在寻找“更好的流”(即具有更多SQL语义的流), 请查看jOOλ ,这是一个将SQL窗口函数引入Java的开源库 。

2.使用递归SQL生成数据

公用表表达式(也称为:CTE,在Oracle中也称为子查询因式分解)是在SQL中声明变量的唯一方法(除了仅PostgreSQL和Sybase SQL Anywhere知道的晦涩的WINDOW子句)。

这是一个强大的概念。 极其强大。 考虑以下语句:

-- Table variables
WITH t1(v1, v2) AS (SELECT 1, 2),t2(w1, w2) AS (SELECT v1 * 2, v2 * 2FROM t1)
SELECT *
FROM t1, t2

它产生

v1   v2   v3   v4
-----------------1    2    2    4

使用简单的WITH子句,您可以指定表变量的列表(记住:所有内容都是一个表),它们甚至可能相互依赖。

这很容易理解。 这使CTE(公用表表达式)已经非常有用,但是真正令人敬畏的是允许它们进行递归! 考虑以下PostgreSQL示例:

WITH RECURSIVE t(v) AS (SELECT 1     -- Seed RowUNION ALLSELECT v + 1 -- RecursionFROM t
)
SELECT v
FROM t
LIMIT 5

它产生

v
---12345

它是如何工作的? 一旦您浏览了许多关键字,这相对容易。 您定义一个公共表表达式,该表表达式恰好具有两个UNION ALL子查询。

我通常将第一个UNION ALL子查询称为“种子行”。 它“种子”(初始化)递归。 它可以产生一行或几行,之后我们将在这些行上递归。 请记住:所有内容都是一个表,因此我们的递归将发生在整个表上,而不是单个行/值上。

第二个UNION ALL子查询是递归发生的地方。 如果仔细观察,您会发现它从t选择。 也就是说,第二个子查询被允许从我们即将声明的CTE中进行选择。 递归地。 因此,它还可以访问列v ,该列已经由使用它的CTE声明。

在我们的示例中,我们使用行(1)作为递归的种子,然后通过添加v + 1进行递归。 然后,通过设置LIMIT 5 (在使用现场, 请注意可能无限的递归,就像Java 8 Streams一样 ),在使用站点停止递归 。

旁注:图灵完整性

递归CTE使SQL:1999完全完成,这意味着任何程序都可以用SQL编写! (如果你够疯狂的话)

一个经常在博客上出现的令人印象深刻的示例:Mandelbrot集,例如,如http://explainextended.com/2013/12/31/happy-new-year-5/

WITH RECURSIVE q(r, i, rx, ix, g) AS (SELECT r::DOUBLE PRECISION * 0.02, i::DOUBLE PRECISION * 0.02, .0::DOUBLE PRECISION      , .0::DOUBLE PRECISION, 0FROM generate_series(-60, 20) r, generate_series(-50, 50) iUNION ALLSELECT r, i, CASE WHEN abs(rx * rx + ix * ix) <= 2 THEN rx * rx - ix * ix END + r, CASE WHEN abs(rx * rx + ix * ix) <= 2 THEN 2 * rx * ix END + i, g + 1FROM qWHERE rx IS NOT NULL AND g < 99
)
SELECT array_to_string(array_agg(s ORDER BY r), '')
FROM (SELECT i, r, substring(' .:-=+*#%@', max(g) / 10 + 1, 1) sFROM qGROUP BY i, r
) q
GROUP BY i
ORDER BY i

在PostgreSQL上运行以上代码,您将获得类似

.-.:-.......==..*.=.::-@@@@@:::.:.@..*-.         =. ...=...=...::+%.@:@@@@@@@@@@@@@+*#=.=:+-.      ..-  .:.:=::*....@@@@@@@@@@@@@@@@@@@@@@@@=@@.....::...:. ...*@@@@=.@:@@@@@@@@@@@@@@@@@@@@@@@@@@=.=....:...::..::@@@@@:-@@@@@@@@@@@@@@@@@@@@@@@@@@@@:@..-:@=*:::..-@@@@@-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.=@@@@=..:...@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:@@@@@:.. ....:-*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@::  .....@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-..  .....@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-:...  .--:+.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@...  .==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-..  ..+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-#.  ...=+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.. -.=-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@..:.*%:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:@-.    ..:...           ..-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
..............        ....-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%@=
.--.-.....-=.:..........::@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@..
..=:-....=@+..=.........@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:.
.:+@@::@==@-*:%:+.......:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
::@@@-@@@@@@@@@-:=.....:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:
.:@@@@@@@@@@@@@@@=:.....%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.:@@@@@@@@@@@@@@@@@-...:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:-
:@@@@@@@@@@@@@@@@@@@-..%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
%@@@@@@@@@@@@@@@@@@@-..-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
@@@@@@@@@@@@@@@@@@@@@::+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+
@@@@@@@@@@@@@@@@@@@@@@:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@..
@@@@@@@@@@@@@@@@@@@@@@-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.

令人印象深刻,是吗?

3.运行总计计算

该博客充满了运行示例 。 它们是学习高级SQL的一些最具教育意义的示例,因为至少有十二种方法可以实现运行总计。

从概念上讲,运行总计很容易理解。

在Microsoft Excel中,您只需计算两个先前(或后续)值的总和(或差),然后使用有用的十字光标将该公式拉入整个电子表格。 您通过电子表格“运行”总计。 “总计”。

在SQL中,最好的方法是使用窗口函数,这是该博客多次讨论的另一个主题 。

窗口函数是一个强大的概念–起初并不容易理解,但实际上,它们确实非常简单:

窗口函数是相对于由SELECT转换的当前行的行的子集的聚合/排名

而已。

本质上,这意味着窗口函数可以对当前行“上方”或“下方”的行执行计算。 但是,与普通的聚合和GROUP BY不同,它们不转换行,这使它们非常有用。

语法可以总结如下,其中各个部分是可选的

function(...) OVER (PARTITION BY ...ORDER BY ...ROWS BETWEEN ... AND ...
)

因此,我们有任何类型的函数(稍后将看到此类函数的示例),然后是此OVER()子句,该子句指定了窗口。 即,此OVER()子句定义:

  • PARTITION :仅将当前行位于同一分区中的行作为窗口
  • ORDER :可以独立于我们选择的顺序订购窗口
  • ROWS (或RANGE )框架定义:可以将窗口限制为固定数量的“前”和“后”行

窗口功能就是这些。

现在,这如何帮助我们计算运行总额? 考虑以下数据:

| ID   | VALUE_DATE | AMOUNT |    BALANCE |
|------|------------|--------|------------|
| 9997 | 2014-03-18 |  99.17 |   19985.81 |
| 9981 | 2014-03-16 |  71.44 |   19886.64 |
| 9979 | 2014-03-16 | -94.60 |   19815.20 |
| 9977 | 2014-03-16 |  -6.96 |   19909.80 |
| 9971 | 2014-03-15 | -65.95 |   19916.76 |

假设BALANCE是我们要根据AMOUNT计算的

直观地,我们可以立即看到以下情况成立:

因此,以通俗的英语来说,任何余额都可以使用以下伪SQL表示:

TOP_BALANCE - SUM(AMOUNT) OVER ("all the rows on top of the current row"
)

在实际SQL中,将这样编写:

SUM(t.amount) OVER (PARTITION BY t.account_id ORDER BY     t.value_date DESC,t.id         DESCROWS BETWEEN UNBOUNDED PRECEDINGAND     1         PRECEDING
)

说明:

  • 该分区将计算每个银行帐户的总和,而不是整个数据集的总和
  • 该排序将确保在求和之前对事务进行排序(在分区内)
  • rows子句将在求和之前仅考虑前面的行(在分区内,按照顺序排列)

所有这些都将在内存中发生,这些内存已存储在您已在FROM .. WHERE等子句中选择的数据集上,因此速度非常快。

间奏曲

在继续进行其他所有很棒的技巧之前,请考虑以下问题:我们已经看到

  • (递归)公用表表达式(CTE)
  • 视窗功能

这两个功能是:

  • 太棒了
  • 极其强大
  • 陈述式
  • SQL标准的一部分
  • 在大多数流行的RDBMS中可用(MySQL除外)
  • 非常重要的构建基块

如果可以从本文得出结论,那就是您应该完全了解现代SQL的这两个构建基块的事实。 为什么? 因为:

4.找到最大的无间隙的序列

Stack Overflow具有此很好的功能,可以激发人们尽可能长时间地停留在其网站上。 徽章:

对于比例,您可以看到我有多少个徽章。 吨。

您如何计算这些徽章? 让我们来看看“爱好者”和“狂热者”。 这些徽章将奖励给在平台上连续花费特定天数的任何人。 无论婚礼日期或妻子的生日如何,您都必须登录,否则计数器将再次从零开始。

现在,当我们进行声明式编程时,我们不再关心维护任何状态计数器和内存中计数器。 我们想以在线分析SQL的形式表达这一点。 即考虑以下数据:

| LOGIN_TIME          |
|---------------------|
| 2014-03-18 05:37:13 |
| 2014-03-16 08:31:47 |
| 2014-03-16 06:11:17 |
| 2014-03-16 05:59:33 |
| 2014-03-15 11:17:28 |
| 2014-03-15 10:00:11 |
| 2014-03-15 07:45:27 |
| 2014-03-15 07:42:19 |
| 2014-03-14 09:38:12 |

那没有太大帮助。 让我们从时间戳中删除小时。 这很简单:

SELECT DISTINCT cast(login_time AS DATE) AS login_date
FROM logins
WHERE user_id = :user_id

产生:

| LOGIN_DATE |
|------------|
| 2014-03-18 |
| 2014-03-16 |
| 2014-03-15 |
| 2014-03-14 |

现在,我们已经了解了窗口函数,我们只需向每个日期添加一个简单的行号:

SELECTlogin_date,row_number() OVER (ORDER BY login_date)
FROM login_dates

产生:

| LOGIN_DATE | RN |
|------------|----|
| 2014-03-18 |  4 |
| 2014-03-16 |  3 |
| 2014-03-15 |  2 |
| 2014-03-14 |  1 |

还是容易。 现在,如果不是将这些值分开选择,而是减去它们,会发生什么呢?

SELECTlogin_date -row_number() OVER (ORDER BY login_date)
FROM login_dates

我们得到这样的东西:

| LOGIN_DATE | RN | GRP        |
|------------|----|------------|
| 2014-03-18 |  4 | 2014-03-14 |
| 2014-03-16 |  3 | 2014-03-13 |
| 2014-03-15 |  2 | 2014-03-13 |
| 2014-03-14 |  1 | 2014-03-13 |

哇。 有趣。 因此, 14 - 1 = 13 15 - 2 = 13 16 - 3 = 13 ,但18 - 4 = 14 。 没有人能比总督说得更好:

此行为有一个简单的示例:

  1. ROW_NUMBER()永远不会有差距。 就是这样定义的
  2. 但是,我们的数据确实

因此,当我们从“连续”日期的“无间隙”系列中减去一系列“无间隙”的连续整数时,对于每个连续日期的“无间隙”子系列,我们将获得相同的日期,并且将再次获得新的日期,其中日期系列存在差距。

这意味着我们现在可以简单地按以下任意日期值进行GROUP BY

SELECTmin(login_date), max(login_date),max(login_date) - min(login_date) + 1 AS length
FROM login_date_groups
GROUP BY grp
ORDER BY length DESC

我们完成了。 发现了最大的连续日期系列,没有间隔:

| MIN        | MAX        | LENGTH |
|------------|------------|--------|
| 2014-03-14 | 2014-03-16 |      3 |
| 2014-03-18 | 2014-03-18 |      1 |

完整查询为:

WITH login_dates AS (SELECT DISTINCT cast(login_time AS DATE) login_date FROM logins WHERE user_id = :user_id),login_date_groups AS (SELECT login_date,login_date - row_number() OVER (ORDER BY login_date) AS grpFROM login_dates)
SELECT min(login_date), max(login_date), max(login_date) - min(login_date) + 1 AS length
FROM login_date_groups
GROUP BY grp
ORDER BY length DESC

最后一点也不难,对吧? 当然,有了这个主意会改变一切,但是查询本身确实非常非常简单而优雅。 没有比这更精简的方法可以实现某些命令式算法了。

ew。

5.查找系列的长度

以前,我们已经看到了一系列连续的值。 这很容易处理,因为我们可以滥用整数的连续性。 如果“系列”的定义不太直观,又有几个系列包含相同的值,该怎么办? 考虑以下数据,其中LENGTH是我们要计算的每个序列的长度:

| ID   | VALUE_DATE | AMOUNT |     LENGTH |
|------|------------|--------|------------|
| 9997 | 2014-03-18 |  99.17 |          2 |
| 9981 | 2014-03-16 |  71.44 |          2 |
| 9979 | 2014-03-16 | -94.60 |          3 |
| 9977 | 2014-03-16 |  -6.96 |          3 |
| 9971 | 2014-03-15 | -65.95 |          3 |
| 9964 | 2014-03-15 |  15.13 |          2 |
| 9962 | 2014-03-15 |  17.47 |          2 |
| 9960 | 2014-03-15 |  -3.55 |          1 |
| 9959 | 2014-03-14 |  32.00 |          1 |

是的,你猜对了。 连续(按ID排序)行具有相同的SIGN(AMOUNT)的事实定义了“系列”。 再次检查格式如下的数据:

| ID   | VALUE_DATE | AMOUNT |     LENGTH |
|------|------------|--------|------------|
| 9997 | 2014-03-18 | +99.17 |          2 |
| 9981 | 2014-03-16 | +71.44 |          2 || 9979 | 2014-03-16 | -94.60 |          3 |
| 9977 | 2014-03-16 | - 6.96 |          3 |
| 9971 | 2014-03-15 | -65.95 |          3 || 9964 | 2014-03-15 | +15.13 |          2 |
| 9962 | 2014-03-15 | +17.47 |          2 || 9960 | 2014-03-15 | - 3.55 |          1 || 9959 | 2014-03-14 | +32.00 |          1 |

我们该怎么做呢? “简单”&#55357;&#56841; 首先,让我们摆脱所有的噪音,并添加另一个行号:

SELECT id, amount,sign(amount) AS sign,row_number() OVER (ORDER BY id DESC) AS rn
FROM trx

这将给我们:

| ID   | AMOUNT | SIGN | RN |
|------|--------|------|----|
| 9997 |  99.17 |    1 |  1 |
| 9981 |  71.44 |    1 |  2 || 9979 | -94.60 |   -1 |  3 |
| 9977 |  -6.96 |   -1 |  4 |
| 9971 | -65.95 |   -1 |  5 || 9964 |  15.13 |    1 |  6 |
| 9962 |  17.47 |    1 |  7 || 9960 |  -3.55 |   -1 |  8 || 9959 |  32.00 |    1 |  9 |

现在,下一个目标是生成下表:

| ID   | AMOUNT | SIGN | RN | LO | HI |
|------|--------|------|----|----|----|
| 9997 |  99.17 |    1 |  1 |  1 |    |
| 9981 |  71.44 |    1 |  2 |    |  2 || 9979 | -94.60 |   -1 |  3 |  3 |    |
| 9977 |  -6.96 |   -1 |  4 |    |    |
| 9971 | -65.95 |   -1 |  5 |    |  5 || 9964 |  15.13 |    1 |  6 |  6 |    |
| 9962 |  17.47 |    1 |  7 |    |  7 || 9960 |  -3.55 |   -1 |  8 |  8 |  8 || 9959 |  32.00 |    1 |  9 |  9 |  9 |

在此表中,我们要将行号值复制到系列“下”的“ LO”,并复制到系列“上”的“ HI”。 为此,我们将使用神奇的LEAD()和LAG()。 LEAD()可以访问当前行中的第n个下一行,而LAG()可以访问当前行中的第n个前一行。 例如:

SELECT lag(v) OVER (ORDER BY v),v, lead(v) OVER (ORDER BY v)
FROM (VALUES (1), (2), (3), (4)
) t(v)

上面的查询产生:

棒极了! 请记住,使用窗口函数,您可以对相对于当前行的行的子集执行排名或汇总。 在LEAD()和LAG()的情况下,我们只需访问相对于当前行的单个行,就给出其偏移量。 在很多情况下这很有用。

继续我们的“ LO”和“ HI”示例,我们可以简单地编写:

SELECT trx.*,CASE WHEN lag(sign) OVER (ORDER BY id DESC) != sign THEN rn END AS lo,CASE WHEN lead(sign) OVER (ORDER BY id DESC) != sign THEN rn END AS hi,
FROM trx

…我们将“前一个”符号( lag(sign) )与“当前”符号( sign )进行比较。 如果它们不同,则将行号放在“ LO”中,因为这是我们系列的下限。

然后,我们将“下一个”符号( lead(sign) )与“当前”符号( sign )进行比较。 如果它们不同,则将行号放在“ HI”中,因为这是我们系列的上限。

最后,进行一些无聊的NULL处理以使一切正确,我们完成了:

SELECT -- With NULL handling...trx.*,CASE WHEN coalesce(lag(sign) OVER (ORDER BY id DESC), 0) != sign THEN rn END AS lo,CASE WHEN coalesce(lead(sign) OVER (ORDER BY id DESC), 0) != sign THEN rn END AS hi,
FROM trx

下一步。 我们希望“ LO”和“ HI”出现在所有行中,而不仅仅是在系列的“下限”和“上限”处。 例如:

| ID   | AMOUNT | SIGN | RN | LO | HI |
|------|--------|------|----|----|----|
| 9997 |  99.17 |    1 |  1 |  1 |  2 |
| 9981 |  71.44 |    1 |  2 |  1 |  2 || 9979 | -94.60 |   -1 |  3 |  3 |  5 |
| 9977 |  -6.96 |   -1 |  4 |  3 |  5 |
| 9971 | -65.95 |   -1 |  5 |  3 |  5 || 9964 |  15.13 |    1 |  6 |  6 |  7 |
| 9962 |  17.47 |    1 |  7 |  6 |  7 || 9960 |  -3.55 |   -1 |  8 |  8 |  8 || 9959 |  32.00 |    1 |  9 |  9 |  9 |

我们正在使用至少在Redshift,Sybase SQL Anywhere,DB2,Oracle中可用的功能。 我们正在使用可以传递给某些窗口函数的“ IGNORE NULLS”子句:

SELECT trx.*,last_value (lo) IGNORE NULLS OVER (ORDER BY id DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS lo,first_value(hi) IGNORE NULLS OVER (ORDER BY id DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS hi
FROM trx

很多关键字! 但是本质始终是相同的。 从任何给定的“当前”行中,我们查看所有“先前值”( ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ),但忽略所有空值。 从这些先前值中,我们取最后一个值,这就是我们新的“ LO”值。 换句话说,我们采用“最近的”“ LO”值。

与“ HI”相同。 从任何给定的“当前”行中,我们查看所有“后续值”( ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING行之间的行),但忽略所有空值。 从后续值中,我们取第一个值,这就是我们新的“ HI”值。 换句话说,我们采用“最近的”“ HI”值。

在Powerpoint中解释:

使它100%正确,并带有一些无聊的NULL修饰:

SELECT -- With NULL handling...trx.*,coalesce(last_value (lo) IGNORE NULLS OVER (ORDER BY id DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), rn) AS lo,coalesce(first_value(hi) IGNORE NULLS OVER (ORDER BY id DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING), rn) AS hi
FROM trx

最后,我们只是在做最后一个小步骤,请记住偏离1的错误:

SELECTtrx.*,1 + hi - lo AS length
FROM trx

我们完成了。 这是我们的结果:

| ID   | AMOUNT | SIGN | RN | LO | HI | LENGTH|
|------|--------|------|----|----|----|-------|
| 9997 |  99.17 |    1 |  1 |  1 |  2 |     2 |
| 9981 |  71.44 |    1 |  2 |  1 |  2 |     2 |
| 9979 | -94.60 |   -1 |  3 |  3 |  5 |     3 |
| 9977 |  -6.96 |   -1 |  4 |  3 |  5 |     3 |
| 9971 | -65.95 |   -1 |  5 |  3 |  5 |     3 |
| 9964 |  15.13 |    1 |  6 |  6 |  7 |     2 |
| 9962 |  17.47 |    1 |  7 |  6 |  7 |     2 |
| 9960 |  -3.55 |   -1 |  8 |  8 |  8 |     1 |
| 9959 |  32.00 |    1 |  9 |  9 |  9 |     1 |

和完整的查询在这里:

WITH trx1(id, amount, sign, rn) AS (SELECT id, amount, sign(amount), row_number() OVER (ORDER BY id DESC)FROM trx),trx2(id, amount, sign, rn, lo, hi) AS (SELECT trx1.*,CASE WHEN coalesce(lag(sign) OVER (ORDER BY id DESC), 0) != sign THEN rn END,CASE WHEN coalesce(lead(sign) OVER (ORDER BY id DESC), 0) != sign THEN rn ENDFROM trx1)
SELECT trx2.*, 1- last_value (lo) IGNORE NULLS OVER (ORDER BY id DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)+ first_value(hi) IGNORE NULLS OVER (ORDER BY id DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
FROM trx2

嗯 这个SQL事情的确开始变得有趣!

准备更多吗?

6. SQL的子集总和问题

这是我最喜欢的!

什么是子集和问题? 在这里找到有趣的解释:
https://xkcd.com/287

还有一个无聊的人:
https://zh.wikipedia.org/wiki/Subset_sum_problem

本质上,对于所有这些总数……

| ID | TOTAL |
|----|-------|
|  1 | 25150 |
|  2 | 19800 |
|  3 | 27511 |

…我们希望找到可能的“最佳”(即最接近)总和,包括以下各项的任意组合:

| ID   |  ITEM |
|------|-------|
|    1 |  7120 |
|    2 |  8150 |
|    3 |  8255 |
|    4 |  9051 |
|    5 |  1220 |
|    6 | 12515 |
|    7 | 13555 |
|    8 |  5221 |
|    9 |   812 |
|   10 |  6562 |

由于您很快就可以进行心理数学处理,因此您立即算出了这些都是最好的总和:

| TOTAL |  BEST | CALCULATION
|-------|-------|--------------------------------
| 25150 | 25133 | 7120 + 8150 + 9051 + 812
| 19800 | 19768 | 1220 + 12515 + 5221 + 812
| 27511 | 27488 | 8150 + 8255 + 9051 + 1220 + 812

如何使用SQL? 简单。 只需创建一个包含所有2 n个 *可能*和的CTE,然后为每个TOTAL找到最接近的一个:

-- All the possible 2N sums
WITH sums(sum, max_id, calc) AS (...)-- Find the best sum per “TOTAL”
SELECT totals.total,something_something(total - sum) AS best,something_something(total - sum) AS calc
FROM draw_the_rest_of_the_*bleep*_owl

在阅读本文时,您可能像我的朋友在这里:

但请放心,解决方案同样不是那么难(尽管由于算法的性质而无法执行):

WITH sums(sum, id, calc) AS (SELECT item, id, to_char(item) FROM itemsUNION ALLSELECT item + sum, items.id, calc || ' + ' || itemFROM sums JOIN items ON sums.id < items.id
)
SELECT totals.id,totals.total,min (sum) KEEP (DENSE_RANK FIRST ORDER BY abs(total - sum)) AS best,min (calc) KEEP (DENSE_RANK FIRST ORDER BY abs(total - sum)) AS calc,
FROM totals
CROSS JOIN sums
GROUP BY totals.id, totals.total

在本文中,我将不解释该解决方案的详细信息,因为该示例摘自您可以在此处找到的上一篇文章:

如何使用SQL查找最近的子集总和

喜欢阅读详细信息,但请务必返回此处了解其余4个技巧:

7.封顶总计

到目前为止,我们已经看到了如何使用窗口函数使用SQL计算“常规”运行总计。 那很简单。 现在,如果我们将运行总计限制为永远不会低于零,那又如何呢? 本质上,我们要计算此:

| DATE       | AMOUNT | TOTAL |
|------------|--------|-------|
| 2012-01-01 |    800 |   800 |
| 2012-02-01 |   1900 |  2700 |
| 2012-03-01 |   1750 |  4450 |
| 2012-04-01 | -20000 |     0 |
| 2012-05-01 |    900 |   900 |
| 2012-06-01 |   3900 |  4800 |
| 2012-07-01 |  -2600 |  2200 |
| 2012-08-01 |  -2600 |     0 |
| 2012-09-01 |   2100 |  2100 |
| 2012-10-01 |  -2400 |     0 |
| 2012-11-01 |   1100 |  1100 |
| 2012-12-01 |   1300 |  2400 |

所以,当大的负面AMOUNT -20000中扣除,而不是显示真实TOTAL-15550 ,我们只是显示0 。 换句话说(或数据集):

| DATE       | AMOUNT | TOTAL |
|------------|--------|-------|
| 2012-01-01 |    800 |   800 | GREATEST(0,    800)
| 2012-02-01 |   1900 |  2700 | GREATEST(0,   2700)
| 2012-03-01 |   1750 |  4450 | GREATEST(0,   4450)
| 2012-04-01 | -20000 |     0 | GREATEST(0, -15550)
| 2012-05-01 |    900 |   900 | GREATEST(0,    900)
| 2012-06-01 |   3900 |  4800 | GREATEST(0,   4800)
| 2012-07-01 |  -2600 |  2200 | GREATEST(0,   2200)
| 2012-08-01 |  -2600 |     0 | GREATEST(0,   -400)
| 2012-09-01 |   2100 |  2100 | GREATEST(0,   2100)
| 2012-10-01 |  -2400 |     0 | GREATEST(0,   -300)
| 2012-11-01 |   1100 |  1100 | GREATEST(0,   1100)
| 2012-12-01 |   1300 |  2400 | GREATEST(0,   2400)

我们将如何做?

究竟。 使用模糊的,特定于供应商SQL。 在这种情况下,我们使用的是Oracle SQL

它是如何工作的? 出奇的简单!

只要在任何表后面添加MODEL ,就可以打开一堆很棒SQL蠕虫!

SELECT ... FROM some_table-- Put this after any table
MODEL ...

一旦将MODEL放到那里,就可以像在Microsoft Excel中一样直接在SQL语句中实现电子表格逻辑。

以下三个条款是最有用和最广泛使用的(即,这个星球上的任何人每年1-2个):

MODEL-- The spreadsheet dimensionsDIMENSION BY ...-- The spreadsheet cell typeMEASURES ...-- The spreadsheet formulasRULES ...

这三个附加条款中每一个的含义最好再用幻灯片进行解释。

DIMENSION BY子句指定电子表格的尺寸。 与MS Excel不同,Oracle中可以具有任意多个维度:

MEASURES子句指定电子表格的每个单元格中可用的值。 与MS Excel不同,您可以在Oracle的每个单元格中有一个完整的元组,而不仅仅是一个值。

RULES子句指定适用于电子表格中每个单元格的公式。 与MS Excel不同,这些规则/公式集中在一个地方,而不是放在每个单元格内:

这种设计使MODEL比MS Excel更难使用,但如果您敢的话,它的功能要强大得多。 整个查询将“平凡”:

SELECT *
FROM (SELECT date, amount, 0 AS totalFROM amounts
)
MODEL DIMENSION BY (row_number() OVER (ORDER BY date) AS rn)MEASURES (date, amount, total)RULES (total[any] = greatest(0,coalesce(total[cv(rn) - 1], 0) + amount[cv(rn)]))

整个功能是如此强大,它附带了Oracle自己的白皮书,因此,请不要阅读这篇优秀的白皮书,而不是在本文中进一步解释。

  • http://www.oracle.com/technetwork/middleware/bi-foundation/10gr1-twp-bi-dw-sqlmodel-131067.pdf

8.时间序列模式识别

如果您涉及欺诈检测或对大数据集进行实时分析的任何其他领域,那么时间序列模式识别对于您而言当然不是一个新名词。

如果我们查看“系列长度”数据集,则可能需要在时间序列上针对复杂事件生成触发器,如下所示:

|   ID | VALUE_DATE |  AMOUNT | LEN | TRIGGER
|------|------------|---------|-----|--------
| 9997 | 2014-03-18 | + 99.17 |   1 |
| 9981 | 2014-03-16 | - 71.44 |   4 |
| 9979 | 2014-03-16 | - 94.60 |   4 |      x
| 9977 | 2014-03-16 | -  6.96 |   4 |
| 9971 | 2014-03-15 | - 65.95 |   4 |
| 9964 | 2014-03-15 | + 15.13 |   3 |
| 9962 | 2014-03-15 | + 17.47 |   3 |
| 9960 | 2014-03-15 | +  3.55 |   3 |
| 9959 | 2014-03-14 | - 32.00 |   1 |

上面触发的规则是:

如果事件发生3次以上,则触发该事件的第3 重复。

类似于先前的MODEL子句,我们可以使用已添加到Oracle 12c的Oracle特定子句来实现:

SELECT ... FROM some_table-- Put this after any table to pattern-match
-- the table’s contents
MATCH_RECOGNIZE (...)

MATCH_RECOGNIZE的最简单的应用程序包括以下子条款:

SELECT *
FROM series
MATCH_RECOGNIZE (-- Pattern matching is done in this orderORDER BY ...-- These are the columns produced by matchesMEASURES ...-- A short specification of what rows are-- returned from each matchALL ROWS PER MATCH-- «Regular expressions» of events to matchPATTERN (...)-- The definitions of «what is an event»DEFINE ...
)

听起来很疯狂。 让我们看一些示例子句实现

SELECT *
FROM series
MATCH_RECOGNIZE (ORDER BY idMEASURES classifier() AS trgALL ROWS PER MATCHPATTERN (S (R X R+)?)DEFINER AS sign(R.amount) = prev(sign(R.amount)),X AS sign(X.amount) = prev(sign(X.amount))
)

我们在这里做什么?

  • 我们通过ID对表进行排序,这是我们要匹配事件的顺序。 简单。
  • 然后,我们指定结果所需的值。 我们需要“ MEASURE” trg,它被定义为分类器,即以后将在PATTERN使用的文字。 另外,我们希望匹配中的所有行。
  • 然后,我们指定类似正则表达式的模式。 该模式是事件“ S”代表开始,然后是“ R”代表重复,“ X”代表我们的特殊事件X,然后是一个或多个“ R”代表再次重复。 如果整个模式匹配,则得到SRXR或SRXRR或SRXRRR,即X将位于一系列长度> = 4的第三个位置
  • 最后,我们定义R和X为同一件事:事件时SIGN(AMOUNT)当前行的相同SIGN(AMOUNT)上一行的。 我们不必定义“ S”。 “ S”仅是其他任何一行。

该查询将神奇地产生以下输出:

|   ID | VALUE_DATE |  AMOUNT | TRG |
|------|------------|---------|-----|
| 9997 | 2014-03-18 | + 99.17 |   S |
| 9981 | 2014-03-16 | - 71.44 |   R |
| 9979 | 2014-03-16 | - 94.60 |   X |
| 9977 | 2014-03-16 | -  6.96 |   R |
| 9971 | 2014-03-15 | - 65.95 |   S |
| 9964 | 2014-03-15 | + 15.13 |   S |
| 9962 | 2014-03-15 | + 17.47 |   S |
| 9960 | 2014-03-15 | +  3.55 |   S |
| 9959 | 2014-03-14 | - 32.00 |   S |

我们可以在事件流中看到一个“ X”。 正是我们所期望的。 在事件的第三次重复中(相同的符号),其长度> 3。

繁荣!

由于我们实际上并不关心“ S”和“ R”事件,因此就这样删除它们:

SELECT id, value_date, amount, CASE trg WHEN 'X' THEN 'X' END trg
FROM series
MATCH_RECOGNIZE (ORDER BY idMEASURES classifier() AS trgALL ROWS PER MATCHPATTERN (S (R X R+)?)DEFINER AS sign(R.amount) = prev(sign(R.amount)),X AS sign(X.amount) = prev(sign(X.amount))
)

生产:

|   ID | VALUE_DATE |  AMOUNT | TRG |
|------|------------|---------|-----|
| 9997 | 2014-03-18 | + 99.17 |     |
| 9981 | 2014-03-16 | - 71.44 |     |
| 9979 | 2014-03-16 | - 94.60 |   X |
| 9977 | 2014-03-16 | -  6.96 |     |
| 9971 | 2014-03-15 | - 65.95 |     |
| 9964 | 2014-03-15 | + 15.13 |     |
| 9962 | 2014-03-15 | + 17.47 |     |
| 9960 | 2014-03-15 | +  3.55 |     |
| 9959 | 2014-03-14 | - 32.00 |     |

谢谢Oracle!

再说一次,不要指望我能比已经出色的Oracle白皮书更好地解释这一点,如果您仍在使用Oracle 12c,我强烈建议阅读:

  • http://www.oracle.com/ocom/groups/public/@otn/documents/webcontent/1965433.pdf

9.枢纽和取消枢纽

如果您已经读了那么多内容,那么以下内容将非常简单:

这是我们的数据,即演员,电影名称和电影等级:

| NAME      | TITLE           | RATING |
|-----------|-----------------|--------|
| A. GRANT  | ANNIE IDENTITY  | G      |
| A. GRANT  | DISCIPLE MOTHER | PG     |
| A. GRANT  | GLORY TRACY     | PG-13  |
| A. HUDSON | LEGEND JEDI     | PG     |
| A. CRONYN | IRON MOON       | PG     |
| A. CRONYN | LADY STAGE      | PG     |
| B. WALKEN | SIEGE MADRE     | R      |

这就是我们所说的透视:

| NAME      | NC-17 |  PG |   G | PG-13 |   R |
|-----------|-------|-----|-----|-------|-----|
| A. GRANT  |     3 |   6 |   5 |     3 |   1 |
| A. HUDSON |    12 |   4 |   7 |     9 |   2 |
| A. CRONYN |     6 |   9 |   2 |     6 |   4 |
| B. WALKEN |     8 |   8 |   4 |     7 |   3 |
| B. WILLIS |     5 |   5 |  14 |     3 |   6 |
| C. DENCH  |     6 |   4 |   5 |     4 |   5 |
| C. NEESON |     3 |   8 |   4 |     7 |   3 |

观察我们如何按演员分组,然后“透视”每个演员所播放的每个评分的数字电影。与其以“关系”方式(即每个组都是一行)显示,我们将整个事物透视成一个整体。每组列。 我们可以这样做,因为我们事先知道所有可能的组。

取消透视是相反的,当从上面开始时,我们想回到“每组行数”表示形式:

| NAME      | RATING | COUNT |
|-----------|--------|-------|
| A. GRANT  | NC-17  |     3 |
| A. GRANT  | PG     |     6 |
| A. GRANT  | G      |     5 |
| A. GRANT  | PG-13  |     3 |
| A. GRANT  | R      |     6 |
| A. HUDSON | NC-17  |    12 |
| A. HUDSON | PG     |     4 |

实际上非常简单。 这是我们在PostgreSQL中的做法:

SELECT first_name, last_name,count(*) FILTER (WHERE rating = 'NC-17') AS "NC-17",count(*) FILTER (WHERE rating = 'PG'   ) AS "PG",count(*) FILTER (WHERE rating = 'G'    ) AS "G",count(*) FILTER (WHERE rating = 'PG-13') AS "PG-13",count(*) FILTER (WHERE rating = 'R'    ) AS "R"
FROM actor AS a
JOIN film_actor AS fa USING (actor_id)
JOIN film AS f USING (film_id)
GROUP BY actor_id

我们可以在聚合函数中附加一个简单的FILTER子句,以便仅计算一些数据。

在所有其他数据库中,我们将这样做:

SELECT first_name, last_name,count(CASE rating WHEN 'NC-17' THEN 1 END) AS "NC-17",count(CASE rating WHEN 'PG'    THEN 1 END) AS "PG",count(CASE rating WHEN 'G'     THEN 1 END) AS "G",count(CASE rating WHEN 'PG-13' THEN 1 END) AS "PG-13",count(CASE rating WHEN 'R'     THEN 1 END) AS "R"
FROM actor AS a
JOIN film_actor AS fa USING (actor_id)
JOIN film AS f USING (film_id)
GROUP BY actor_id

这里的好处是,聚合函数通常只考虑非NULL值,所以如果我们让所有的值NULL是不是每个合并有趣,我们将得到同样的结果。

现在,如果您使用的是SQL Server或Oracle,则可以使用内置的PIVOTUNPIVOT子句。 同样,与MODELMATCH_RECOGNIZE ,只需在表后追加此新关键字,即可得到相同的结果:

-- PIVOTING
SELECT something, something
FROM some_table
PIVOT (count(*) FOR rating IN ('NC-17' AS "NC-17", 'PG'    AS "PG", 'G'     AS "G", 'PG-13' AS "PG-13", 'R'     AS "R")
)-- UNPIVOTING
SELECT something, something
FROM some_table
UNPIVOT (count    FOR rating IN ("NC-17" AS 'NC-17', "PG"    AS 'PG', "G"     AS 'G', "PG-13" AS 'PG-13', "R"     AS 'R')
)

简单。 下一个。

10.滥用XML和JSON

首先

JSON只是具有较少功能和较少语法的XML

现在,每个人都知道XML很棒。 因此,推论是:

JSON不太出色

不要使用JSON。

现在,我们已经解决了这一问题,我们可以放心地忽略正在进行的JSON-in-the-the-database-hype(无论如何,大多数人都会在五年内后悔),然后转到最后一个示例。 如何在数据库中执行XML。

这就是我们要做的:

给定原始XML文档,我们要解析该文档,不要嵌套以逗号分隔的每个演员的电影列表,并在单个关系中生成非规范的演员/电影表示形式。

准备。 组。 走。 这是主意。 我们有三个CTE:

WITH RECURSIVEx(v) AS (SELECT '...'::xml),actors(actor_id, first_name, last_name, films) AS (...),films(actor_id, first_name, last_name, film_id, film) AS (...)
SELECT *
FROM films

在第一个中,我们简单地解析XML。 在PostgreSQL中:

WITH RECURSIVEx(v) AS (SELECT '
<actors><actor><first-name>Bud</first-name><last-name>Spencer</last-name><films>God Forgives... I Don’t, Double Trouble, They Call Him Bulldozer</films></actor><actor><first-name>Terence</first-name><last-name>Hill</last-name><films>God Forgives... I Don’t, Double Trouble, Lucky Luke</films></actor>
</actors>'::xml),actors(actor_id, first_name, last_name, films) AS (...),films(actor_id, first_name, last_name, film_id, film) AS (...)
SELECT *
FROM films

简单。

然后,我们做了一些XPath魔术,以从XML结构中提取各个值并将其放入列中:

WITH RECURSIVEx(v) AS (SELECT '...'::xml),actors(actor_id, first_name, last_name, films) AS (SELECTrow_number() OVER (),(xpath('//first-name/text()', t.v))[1]::TEXT,(xpath('//last-name/text()' , t.v))[1]::TEXT,(xpath('//films/text()'     , t.v))[1]::TEXTFROM unnest(xpath('//actor', (SELECT v FROM x))) t(v)),films(actor_id, first_name, last_name, film_id, film) AS (...)
SELECT *
FROM films

还是容易。

最后,只需一点匹配魔术的递归正则表达式模式,就可以完成!

WITH RECURSIVEx(v) AS (SELECT '...'::xml),actors(actor_id, first_name, last_name, films) AS (...),films(actor_id, first_name, last_name, film_id, film) AS (SELECT actor_id, first_name, last_name, 1, regexp_replace(films, ',.+', '')FROM actorsUNION ALLSELECT actor_id, a.first_name, a.last_name, f.film_id + 1,regexp_replace(a.films, '.*' || f.film || ', ?(.*?)(,.+)?', '\1')FROM films AS f JOIN actors AS a USING (actor_id)WHERE a.films NOT LIKE '%' || f.film)
SELECT *
FROM films

让我们总结一下:

结论

本文显示的所有内容都是声明性的。 而且相对容易。 当然,为了使我在这次演讲中达到有趣的效果,我使用了一些夸张SQL,我明确地将一切称为“简单”。 这一点都不容易,您必须练习SQL。 像许多其他语言一样,但是有点困难,因为:

  1. 语法有时会有点尴尬
  2. 声明式思考并不容易。 至少,这是非常不同的

但是一旦掌握了这些知识,使用SQL进行声明式编程就完全值得了,因为您只需描述要从数据库中获得的结果,就可以用非常少的代码来表达数据之间的复杂关系。

那不是很棒吗?

如果那是最重要的事情,请注意,我很高兴访问您的JUG /会议以进行此演讲( 只需与我们联系 ),或者如果您想深入了解这些事情的细节,我们也以公开或内部研讨会的形式提供此演讲 。 保持联系! 我们期待着。

在此处再次查看完整的幻灯片:

Lukas Eder 认为10种您认为不可能SQL技巧

翻译自: https://www.javacodegeeks.com/2016/04/10-sql-tricks-didnt-think-possible.html

sql技巧

sql技巧_您认为不可能的10个SQL技巧相关推荐

  1. mysql如何定义消耗资源多的sql语句_如何查找消耗资源较大的SQL

    对于优化来讲,查找消耗资源较大的SQL至关重要,下面介绍几个之前用到的SQL. 1.从V$SQLAREA中查询最占用资源的查询. select b.username username,a.disk_r ...

  2. python工作技巧_能让你工作事半功倍的python小技巧大合集

    导读:Python是目前世界上最流行的编程语言之一.因为: 1. 它容易学习 2. 它用途超广 3. 它有非常多的开源支持(大量的模块和库) 本文作者 Peter Gleeson 是一名数据科学家,日 ...

  3. 分享图表制作技巧_15个最有用的Windows 10提示和技巧信息图表

    分享图表制作技巧 查看最有用的Windows 10提示和技巧,以快速入门: (Look at the most useful Windows 10 Tips and Tricks for a quic ...

  4. python数据库操作批量sql执行_利用Python如何批量修改数据库执行Sql文件

    利用Python如何批量修改数据库执行Sql文件 来源:中文源码网    浏览: 次    日期:2018年9月2日 [下载文档:  利用Python如何批量修改数据库执行Sql文件.txt ] (友 ...

  5. PostgreSQL 10.1 手册_部分 II. SQL 语言_第 8 章 数据类型_8.10. 位串类型

    8.10. 位串类型 位串就是一串 1 和 0 的串.它们可以用于存储和可视化位掩码.我们有两种类型的 SQL 位类型:bit(n)和bit varying(n),其中 n是一个正整数. bit类型的 ...

  6. SQL进行排序、分组、统计的10个新技巧

    1.使用排序使数据有序 通常,你的所有数据真正需要的仅仅是按某种顺序排列.SQL的ORDER BY语句可以以字母或数字顺序组织数据.因此,相似的值按组排序在一起.然而,这个分组时排序的结果,并不是真的 ...

  7. python创建数据库的sql语句_对python插入数据库和生成插入sql的示例讲解

    如下所示: #-*- encoding:utf-8 -*- import csv import sys,os import pymysql def read_csv(filename): ''' 读取 ...

  8. wordpress汉化技巧_保护您的WordPress网站的6个技巧

    wordpress汉化技巧 WordPress已经为超过30%的互联网提供支持,是世界上增长最快的内容管理系统(CMS),不难看出为什么. 通过编码和插件可以提供大量的自定义功能,一流的SEO以及博客 ...

  9. 高效pycharm使用技巧_您是否正在使用这种高效的采访技巧?

    高效pycharm使用技巧 Linux基金会前首席营销官阿曼达·麦克弗森 ( Amanda McPherson)的一篇有关她最好的面试技巧的帖子,让我想到了我多年前在GNOME董事会任教的面试技巧:关 ...

最新文章

  1. Visual Studio 15改进C++工程加载
  2. 20165203第四周考试
  3. 在并发中练习 Boost.Multiprecision多线程环境相关的测试程序
  4. 日期与时间(C/C++)
  5. Javascript报错Failed to execute ‘querySelectorAll‘ on ‘Document‘: ‘#123456‘ is not a valid sele
  6. linux curl命令验证服务器断点续传支持
  7. linux7 修改服务启动项目命令,centos7服务部署flask项目
  8. screen 命令使用及示例
  9. .NET反射 Type类
  10. Android应用程序开发入门
  11. python使用matplotlib可视化线图(line plot)、使用semilogy函数将Y轴数据处理为对数坐标(logarithmic scale in Matplotlib)
  12. 人工智能、机器学习、神经网络和深度学习的发展历程(下)
  13. 使用python读写文件_使用Python读写文件(指南)
  14. 【小家Spring】Spring AOP之Advisor、PointcutAdvisor、IntroductionAdvisor、IntroductionInterceptor(引介增强)
  15. linux命令vi编辑文件注释掉某一行,请问linux的vi命令进入文本编辑后怎么去删除一行?...
  16. C#高效编程:改进C#代码的50个行之有效的办法(第2版)(奋斗的小鸟)_PDF 电子书
  17. 南邮 OJ 1275 登山机器人问题
  18. selenium报错Message: This version of ChromeDriver only supports Chrome version xx
  19. Nwafu-OJ-1430 Problem a C语言实习题五——5.用指针实现查找二维数组中最大数及其位置
  20. 20230123使AIO-3568J开发板在Android12下永不休眠

热门文章

  1. 通过Hive的案例了解Hive在工作中的使用
  2. Python自动发邮件总结及说明
  3. 此文件是二进制文件或使用了不支持的文本编码_计算机的基本原理(组成、发展、DOS、交互、文件、进制、环境)...
  4. SQLServer找不到配置管理器,如何打开配置管理器
  5. for语句java n_JAVA循环for语句
  6. redmine mysql 配置_Redmine 2.0.3 安装配置
  7. unity3d OpenCVForUnity(一)
  8. 浅析DirectX11技术带给图形业界的改变
  9. 【机器学习】解决机器学习中OneVsRestClassifier的网格调参Invalid parameter max_depth for estimator OneVsRestClassifier
  10. 吴恩达机器学习(一)机器学习的入门介绍