当前位置:网站首页>Task03: more complex query (2)

Task03: more complex query (2)

2022-06-10 08:49:00 JxWang05

Tutorial address

https://github.com/datawhalechina/wonderful-sql
https://gitee.com/datawhalechina/wonderful-sql

3. Various functions

mysql> show tables;
+-------------------+
| Tables_in_shop    |
+-------------------+
| ViewPractice5_1   |
| ViewPractice5_2   |
| chars             |
| empskills         |
| inventoryproduct  |
| product           |
| product2          |
| productcopy       |
| productins        |
| productsum        |
| producttype       |
| samplelike        |
| samplemath        |
| samplestr         |
| shop_product      |
| shopproduct       |
| skills            |
| user              |
| view_product      |
| view_shop_product |
+-------------------+
20 rows in set (0.01 sec)

mysql> select * from samplemath;
+----------+------+------+
| m        | n    | p    |
+----------+------+------+
|  500.000 |    0 | NULL |
| -180.000 |    0 | NULL |
|     NULL | NULL | NULL |
|     NULL |    7 |    3 |
|     NULL |    5 |    2 |
|     NULL |    4 | NULL |
|    8.000 | NULL |    3 |
|    2.270 |    1 | NULL |
|    5.555 |    2 | NULL |
|     NULL |    1 | NULL |
|    8.760 | NULL | NULL |
+----------+------+------+
11 rows in set (0.00 sec)

First look at the watch , Already there. , Then there is no need to build any more

3.1 Arithmetic functions

3.1.1 The absolute value

Let's find an absolute value first

mysql> select m, abs(m) as abs_col from samplemath;
+----------+---------+
| m        | abs_col |
+----------+---------+
|  500.000 | 500.000 |
| -180.000 | 180.000 |
|     NULL |    NULL |
|     NULL |    NULL |
|     NULL |    NULL |
|     NULL |    NULL |
|    8.000 |   8.000 |
|    2.270 |   2.270 |
|    5.555 |   5.555 |
|     NULL |    NULL |
|    8.760 |   8.760 |
+----------+---------+
11 rows in set (0.02 sec)

null The absolute value of is still null

3.1.2 Seeking remainder

Let's do it again

mysql> select n, p, mod(n,p) as mod_col from samplemath;
+------+------+---------+
| n    | p    | mod_col |
+------+------+---------+
|    0 | NULL |    NULL |
|    0 | NULL |    NULL |
| NULL | NULL |    NULL |
|    7 |    3 |       1 |
|    5 |    2 |       1 |
|    4 | NULL |    NULL |
| NULL |    3 |    NULL |
|    1 | NULL |    NULL |
|    2 | NULL |    NULL |
|    1 | NULL |    NULL |
| NULL | NULL |    NULL |
+------+------+---------+
11 rows in set (0.00 sec)


Decimals cannot be remainder , This operation is only valid for integers

What needs our attention is ,SQL Server It's using % To calculate the remainder , I won't support it mod function

3.1.3 rounding

Next is the rounding operation , Let's keep one decimal place to see

mysql> select m, round(m,1) as round_col from samplemath;
+----------+-----------+
| m        | round_col |
+----------+-----------+
|  500.000 |     500.0 |
| -180.000 |    -180.0 |
|     NULL |      NULL |
|     NULL |      NULL |
|     NULL |      NULL |
|     NULL |      NULL |
|    8.000 |       8.0 |
|    2.270 |       2.3 |
|    5.555 |       5.6 |
|     NULL |      NULL |
|    8.760 |       8.8 |
+----------+-----------+
11 rows in set (0.00 sec)

It should be noted that , We'd better use numbers directly to specify the number of decimal places to keep

If you use variables, there may be errors

3.2 String function

The table has been built before

mysql> select * from samplestr;
+-----------+--------+--------+
| str1      | str2   | str3   |
+-----------+--------+--------+
| opx       | rt     | NULL   |
| abc       | def    | NULL   |
|  Yamada       |  Taro    |  Is my    |
| aaa       | NULL   | NULL   |
| NULL      | xyz    | NULL   |
| @!#$% | NULL | NULL |
| ABC       | NULL   | NULL   |
| aBC       | NULL   | NULL   |
| abc Taro    | abc    | ABC    |
| abcdefabc | abc    | ABC    |
| micmic    | i      | I      |
+-----------+--------+--------+
11 rows in set (0.00 sec)

3.2.1 Splicing

First look at it. concat

mysql> select str1, str2, concat(str1,'-',str2) from samplestr;
+-----------+--------+-----------------------+
| str1      | str2   | concat(str1,'-',str2) |
+-----------+--------+-----------------------+
| opx       | rt     | opx-rt                |
| abc       | def    | abc-def               |
|  Yamada       |  Taro    |  Yamada - Taro              |
| aaa       | NULL   | NULL                  |
| NULL      | xyz    | NULL                  |
| @!#$% | NULL | NULL |
| ABC       | NULL   | NULL                  |
| aBC       | NULL   | NULL                  |
| abc Taro    | abc    | abc Taro -abc           |
| abcdefabc | abc    | abcdefabc-abc         |
| micmic    | i      | micmic-i              |
+-----------+--------+-----------------------+
11 rows in set (0.00 sec)

ah , Yes null It doesn't work , Everything else is OK , It seems that you can only connect three columns at most

3.2.2 length

mysql> select str1, length(str1) as len_str1 from samplestr;
+-----------+----------+
| str1      | len_str1 |
+-----------+----------+
| opx       |        3 |
| abc       |        3 |
|  Yamada       |        6 |
| aaa       |        3 |
| NULL      |     NULL |
| @!#$% | 5 |
| ABC       |        3 |
| aBC       |        3 |
| abc Taro    |        9 |
| abcdefabc |        9 |
| micmic    |        6 |
+-----------+----------+
11 rows in set (0.00 sec)

A common measuring length , Nothing to say

3.2.3 toggle case

mysql> select str1, lower(str1) as lower_str1, upper(str1) as upper_str1 from samplestr;
+-----------+------------+------------+
| str1      | lower_str1 | upper_str1 |
+-----------+------------+------------+
| opx       | opx        | OPX        |
| abc       | abc        | ABC        |
|  Yamada       |  Yamada        |  Yamada        |
| aaa       | aaa        | AAA        |
| NULL      | NULL       | NULL       |
| @!#$% | @!#$% | @!#$% |
| ABC       | abc        | ABC        |
| aBC       | abc        | ABC        |
| abc Taro    | abc Taro     | ABC Taro     |
| abcdefabc | abcdefabc  | ABCDEFABC  |
| micmic    | micmic     | MICMIC     |
+-----------+------------+------------+
11 rows in set (0.00 sec)

Only valid for letters , And the valid range is all letters , Contains letters mixed in Chinese

3.2.4 Replace

mysql> select str1, replace(str1,'a','Z') as replace_str1 from samplestr;
+-----------+--------------+
| str1      | replace_str1 |
+-----------+--------------+
| opx       | opx          |
| abc       | Zbc          |
|  Yamada       |  Yamada          |
| aaa       | ZZZ          |
| NULL      | NULL         |
| @!#$% | @!#$% |
| ABC       | ABC          |
| aBC       | ZBC          |
| abc Taro    | Zbc Taro       |
| abcdefabc | ZbcdefZbc    |
| micmic    | micmic       |
+-----------+--------------+
11 rows in set (0.00 sec)

We put the lowercase a Replace all with uppercase Z, The scope covers all letters

3.2.5 Intercept

mysql> select str1, substring(str1,0,1), substring(str1,1,1) from samplestr;
+-----------+---------------------+---------------------+
| str1      | substring(str1,0,1) | substring(str1,1,1) |
+-----------+---------------------+---------------------+
| opx       |                     | o                   |
| abc       |                     | a                   |
|  Yamada       |                     |  mountain                   |
| aaa       |                     | a                   |
| NULL      | NULL                | NULL                |
| @!#$% | | @ |
| ABC       |                     | A                   |
| aBC       |                     | a                   |
| abc Taro    |                     | a                   |
| abcdefabc |                     | a                   |
| micmic    |                     | m                   |
+-----------+---------------------+---------------------+
11 rows in set (0.00 sec)

We can see that the subscript of this string is from 1 At the beginning

The first parameter is the string of characters , The second parameter is the starting point , The third parameter is length

3.2.6 Index interception

mysql> SELECT SUBSTRING_INDEX('www.mysql.com', '.', 2);
+------------------------------------------+
| SUBSTRING_INDEX('www.mysql.com', '.', 2) |
+------------------------------------------+
| www.mysql                                |
+------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('www.mysql.com', '.', 2), '.', -1);
+--------------------------------------------------------------------+
| SUBSTRING_INDEX(SUBSTRING_INDEX('www.mysql.com', '.', 2), '.', -1) |
+--------------------------------------------------------------------+
| mysql                                                              |
+--------------------------------------------------------------------+
1 row in set (0.00 sec)

This function is also very magical , It should be divided according to the separator first

Then the subscript of the segmentation result is from 1 At the beginning , Then get the segmentation result according to the length

3.2.7 repeat

mysql> select str1, repeat(str1,3) as repeat_str1 from samplestr;
+-----------+-----------------------------+
| str1      | repeat_str1                 |
+-----------+-----------------------------+
| opx       | opxopxopx                   |
| abc       | abcabcabc                   |
|  Yamada       |  Yamada Yamada                 |
| aaa       | aaaaaaaaa                   |
| NULL      | NULL                        |
| @!#$% | @!#$%@!#$%@!#$% |
| ABC       | ABCABCABC                   |
| aBC       | aBCaBCaBC                   |
| abc Taro    | abc Taro abc Taro abc Taro        |
| abcdefabc | abcdefabcabcdefabcabcdefabc |
| micmic    | micmicmicmicmicmic          |
+-----------+-----------------------------+
11 rows in set (0.00 sec)

Simply pass a parameter , Just specify the number of repetitions

3.3 Date function

mysql> SELECT CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP;
+--------------+--------------+---------------------+
| CURRENT_DATE | CURRENT_TIME | CURRENT_TIMESTAMP   |
+--------------+--------------+---------------------+
| 2022-05-25   | 16:42:35     | 2022-05-25 16:42:35 |
+--------------+--------------+---------------------+
1 row in set (0.00 sec)

mysql> SELECT CURRENT_TIMESTAMP as now,
    -> EXTRACT(YEAR   FROM CURRENT_TIMESTAMP) AS year,
    -> EXTRACT(MONTH  FROM CURRENT_TIMESTAMP) AS month,
    -> EXTRACT(DAY    FROM CURRENT_TIMESTAMP) AS day,
    -> EXTRACT(HOUR   FROM CURRENT_TIMESTAMP) AS hour,
    -> EXTRACT(MINUTE FROM CURRENT_TIMESTAMP) AS MINute,
    -> EXTRACT(SECOND FROM CURRENT_TIMESTAMP) AS second;
+---------------------+------+-------+------+------+--------+--------+
| now                 | year | month | day  | hour | MINute | second |
+---------------------+------+-------+------+------+--------+--------+
| 2022-05-25 16:42:48 | 2022 |     5 |   25 |   16 |     42 |     48 |
+---------------------+------+-------+------+------+--------+--------+
1 row in set (0.01 sec)

mysql> 

current The prefix correlation function can get the current date 、 Time and timestamp

extract The year() function separates the year from the timestamp 、 month 、 minute 、 second

3.4 Conversion function

Let's take a look at type conversion first

mysql> SELECT CAST('0001' AS SIGNED INTEGER) AS int_col,
    ->  CAST('2009-12-14' AS DATE) AS date_col;
+---------+------------+
| int_col | date_col   |
+---------+------------+
|       1 | 2009-12-14 |
+---------+------------+
1 row in set (0.00 sec)

This is for direct use cast function , Just indicate the type

And then there's another one , transformation null It's worth it , We mentioned it before ,coalesce

mysql> select str3, coalesce(str3,'Zeta') from samplestr;
+--------+-----------------------+
| str3   | coalesce(str3,'Zeta') |
+--------+-----------------------+
| NULL   | Zeta                  |
| NULL   | Zeta                  |
|  Is my    |  Is my                   |
| NULL   | Zeta                  |
| NULL   | Zeta                  |
| NULL   | Zeta                  |
| NULL   | Zeta                  |
| NULL   | Zeta                  |
| ABC    | ABC                   |
| ABC    | ABC                   |
| I      | I                     |
+--------+-----------------------+
11 rows in set (0.00 sec)

4. The predicate

Let's look at the watch first , We built it before

mysql> select * from samplelike;
+--------+
| strcol |
+--------+
| abcdd  |
| abcddd |
| abddc  |
| abdddc |
| ddabc  |
| dddabc |
+--------+
6 rows in set (0.00 sec)

mysql> 

The return value of predicate function is usually Boolean , for example true、false、unknown

4.1 like

This function is mainly used for string query matching

We use it here %, It represents zero or more arbitrary characters

mysql> SELECT *
    -> FROM samplelike
    -> WHERE strcol LIKE 'd%';
+--------+
| strcol |
+--------+
| ddabc  |
| dddabc |
+--------+
2 rows in set (0.00 sec)

For example, the character selected here is d Beginning line

We can also use underscores _ To represent any character

mysql> SELECT *
    -> FROM samplelike
    -> WHERE strcol LIKE 'abdd_';
+--------+
| strcol |
+--------+
| abddc  |
+--------+
1 row in set (0.01 sec)

mysql> SELECT *
    -> FROM samplelike
    -> WHERE strcol LIKE 'abdd%';
+--------+
| strcol |
+--------+
| abddc  |
| abdddc |
+--------+
2 rows in set (0.01 sec)

4.2 between

This is the obvious range query , Contains a critical value

mysql> --  Select the sales unit price as 100~ 1000 Yuan goods 
mysql> SELECT product_name, sale_price
    -> FROM product
    -> WHERE sale_price BETWEEN 100 AND 1000;
+--------------+------------+
| product_name | sale_price |
+--------------+------------+
| T T-shirt           |       1000 |
|  Punch        |        500 |
|  Fork          |        500 |
|  Clean the board        |        880 |
+--------------+------------+
4 rows in set (0.00 sec)

4.3 null Judge

So this is is null and is not null

then isnull() It seems to be a function

You can wrap columns directly in query statements

I remember null Value can be compared with other values , But the default is the smallest

And then you can't use == To judge null value , So use this is null

mysql> SELECT product_name, purchase_price
    -> FROM product
    -> WHERE purchase_price IS NULL;
+--------------+----------------+
| product_name | purchase_price |
+--------------+----------------+
|  Fork          |           NULL |
|  Ball pen        |           NULL |
+--------------+----------------+
2 rows in set (0.00 sec)

4.4 in

If we want to query the data within the specified range , Maybe the first reaction is between, Or use greater than 、 Less than to adjust

But this is a continuous range , If it's discrete , That could be multiple == use or Connect

Fortunately, we still have in, I feel very much like python, The decision value is not in the list

mysql> SELECT product_name, purchase_price
    -> FROM product
    -> WHERE purchase_price IN (320, 500, 5000);
+--------------+----------------+
| product_name | purchase_price |
+--------------+----------------+
| T T-shirt           |            500 |
|  Punch        |            320 |
|  pressure cooker        |           5000 |
+--------------+----------------+
3 rows in set (0.00 sec)

This example is , The inquiry price is 320、500 perhaps 5000 The record of

and , We can also use not To take the opposite

Besides ,in It can also be used in subqueries

Suppose we need to take out the sales unit price of goods on sale in Osaka

mysql> SELECT product_name, sale_price
    -> FROM product
    -> WHERE product_id IN (
    ->   SELECT product_id
    ->   FROM shopproduct
    ->   WHERE shop_id = '000C'
    ->   )
    -> ;
+--------------+------------+
| product_name | sale_price |
+--------------+------------+
|  motion T T-shirt       |       4000 |
|  kitchen knife          |       3000 |
|  Fork          |        500 |
|  Clean the board        |        880 |
+--------------+------------+
4 rows in set (0.00 sec)

This looks more like a join table query

We have to go first shopproduct surface , according to shop_id = ‘000C’, Take out the goods sold in Osaka id

Then go again. product In the table , Put these id The records of , Then show the specified columns

Intuitively, it looks like an associated subquery , But when you think about it, it's not

Let's start here , The feeling here is similar to scalar quantum query , It just returns the feeling of a list

But in the associated sub query , The return result has a certain relationship in it

The example given in the related subquery section is , Query the goods whose selling price is higher than the average price of this category

In short , Subquery gets the average price of each category , If it's just this , It seems impossible to compare

Because every time we read a product , What you want to compare is the average price of the product and its category

So the external query where sentence , Find the average price corresponding to that category to compare , That is, correspondence

Then in the returned results of the associated sub query , We include this relationship

We embed in the subquery p1.product_type = p2.product_type The sentence of

That is, the returned result contains such a corresponding relationship , For external inquiry where Called

4.5 exist

The function of this thing is “ Determine whether there are records that meet certain conditions ”

The requirements are the same as above , All are the prices of goods sold in Osaka

mysql> SELECT product_name, sale_price
    ->   FROM product AS p
    ->  WHERE EXISTS (SELECT *
    ->                  FROM shopproduct AS sp
    ->                 WHERE sp.shop_id = '000C'
    ->                   AND sp.product_id = p.product_id);
+--------------+------------+
| product_name | sale_price |
+--------------+------------+
|  motion T T-shirt       |       4000 |
|  kitchen knife          |       3000 |
|  Fork          |        500 |
|  Clean the board        |        880 |
+--------------+------------+
4 rows in set (0.00 sec)

Oh, roar , What to say, what to say , So this is an associated subquery

We can see in the subquery , from shopproduct Choose Osaka store

then and Appoint sp.product_id = p.product_id, Choose the corresponding id The mapping relationship

Then pass this relationship to the external query , For external query exist To handle mapping relationships

and ,exist Only care about whether records exist , So you may not pay much attention to the selected columns

therefore , We are in sub query select The column of can not be so rigorous

however , Generally speaking , Let's choose * Relatively safe

5. case expression

It's like switch Same conditional branch

First, let's take a look at the most conventional , According to the different values of a field , Different records are processed differently

mysql> SELECT  product_name,
    ->         CASE WHEN product_type = ' clothes ' THEN CONCAT('A : ',product_type)
    ->              WHEN product_type = ' Office Supplies '  THEN CONCAT('B : ',product_type)
    ->              WHEN product_type = ' Kitchenware '  THEN CONCAT('C : ',product_type)
    ->              ELSE NULL
    ->         END AS abc_product_type
    ->   FROM  product;
+--------------+--------------------+
| product_name | abc_product_type   |
+--------------+--------------------+
| T T-shirt           | A :  clothes           |
|  Punch        | B :  Office Supplies       |
|  motion T T-shirt       | A :  clothes           |
|  kitchen knife          | C :  Kitchenware       |
|  pressure cooker        | C :  Kitchenware       |
|  Fork          | C :  Kitchenware       |
|  Clean the board        | C :  Kitchenware       |
|  Ball pen        | B :  Office Supplies       |
+--------------+--------------------+
8 rows in set (0.00 sec)

Above , We vary according to the type of goods , The commodity categories are treated differently

then , It can also achieve the effect similar to row to column , Or display the aggregation results on the column

mysql> --  Perform line to line conversion on the total sales unit price calculated by commodity type 
mysql> SELECT SUM(CASE WHEN product_type = ' clothes ' THEN sale_price ELSE 0 END) AS sum_price_clothes,
    ->        SUM(CASE WHEN product_type = ' Kitchenware ' THEN sale_price ELSE 0 END) AS sum_price_kitchen,
    ->        SUM(CASE WHEN product_type = ' Office Supplies ' THEN sale_price ELSE 0 END) AS sum_price_office
    ->   FROM product;
+-------------------+-------------------+------------------+
| sum_price_clothes | sum_price_kitchen | sum_price_office |
+-------------------+-------------------+------------------+
|              5000 |             11180 |             5500 |
+-------------------+-------------------+------------------+
1 row in set (0.01 sec)

The first column only selects clothes , The second column is kitchen utensils , Display the processing of records of different categories in different columns

I feel like this is a subquery , Every sum It uses sub query to filter a category

We can also further extend the above operations , It is a relatively generalized row to column operation

B. Exercises

B.1

The operation contains NULL when , Whether the result of the operation must become NULL ?

character string 、 The numeric class contains null All the operations are null

B.2

As used in this chapter product( goods ) The table is executed as follows 2 strip SELECT sentence , What kind of results can we get ?

SELECT product_name, purchase_price
FROM product
WHERE purchase_price NOT IN (500, 2800, 5000);

This should be an optional price 500、2800、5000 The name and price of the item

SELECT product_name, purchase_price
FROM product
WHERE purchase_price NOT IN (500, 2800, 5000, NULL);

On the basis of the previous step, an null

But it doesn't seem to work ,null Only use is null Such

The feeling here is similar to == Such

mysql> SELECT product_name, purchase_price
    ->   FROM product
    ->  WHERE purchase_price NOT IN (500, 2800, 5000);
+--------------+----------------+
| product_name | purchase_price |
+--------------+----------------+
|  Punch        |            320 |
|  Clean the board        |            790 |
+--------------+----------------+
2 rows in set (0.00 sec)

mysql> SELECT product_name, purchase_price
    ->   FROM product
    ->  WHERE purchase_price NOT IN (500, 2800, 5000, NULL);
Empty set (0.00 sec)

Sure enough

B.3

According to the sales unit price ( sale_price ) Yes, practice 3.6 Medium product( goods ) The goods in the table are classified as follows .

Low end goods : The sales unit price is in 1000 Below yen (T shirt 、 Office Supplies 、 Fork 、 Clean the board 、 Ball pen )
Mid range goods : The sales unit price is in 1001 Above JPY 3000 Below yen ( kitchen knife )
High end goods : The sales unit price is in 3001 Above JPY ( motion T T-shirt 、 pressure cooker )
Please write down the statistics of the number of goods included in the above categories SELECT sentence , The results are shown below .

Execution results
low_price | mid_price | high_price
----------±----------±-----------
5 | 1 | 2

mysql> SELECT SUM(CASE WHEN purchase_price < 1000 THEN 1 ELSE 0 END) AS low_price,
    ->        SUM(CASE WHEN purchase_price < 1000 OR ISNULL(purchase_price) THEN 1 ELSE 0 END) AS low_price2,
    ->        SUM(CASE WHEN purchase_price > 1000 AND purchase_price < 3000 THEN 1 ELSE 0 END) AS mid_price,
    ->        SUM(CASE WHEN purchase_price > 3000 THEN 1 ELSE 0 END) AS high_price
    ->   FROM product;
+-----------+------------+-----------+------------+
| low_price | low_price2 | mid_price | high_price |
+-----------+------------+-----------+------------+
|         3 |          5 |         2 |          1 |
+-----------+------------+-----------+------------+
1 row in set (0.00 sec)

mysql> 

Maybe my database has changed ? Anyway, the result should mean , But it doesn't match the question

原网站

版权声明
本文为[JxWang05]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/161/202206100834331164.html