私信  •  关注

Bill Karwin

Bill Karwin 最近创建的主题
Bill Karwin 最近回复了
2 年前
回复了 Bill Karwin 创建的主题 » 如果在查询中使用MySQL函数,则在SQLite下Laravel测试失败

CURRENT_TIMESTAMP 是一种符合标准SQL的特殊语法。这就像一个常数(注意缺少 () 这是调用函数时所期望的)。

它由SQLite支持:

SQLite version 3.32.3 2020-06-18 14:16:19
sqlite> select current_timestamp;
2021-10-17 17:16:02

通过MySQL:

Welcome to the MySQL monitor.  Commands end with ; or \g.
Server version: 5.7.34-37-log Homebrew

mysql> select current_timestamp;
+---------------------+
| current_timestamp   |
+---------------------+
| 2021-10-17 17:16:08 |
+---------------------+

请回复您的评论:

必然会有一些函数在不同的SQL实现之间不可移植。“可移植SQL”是一个神话。在每个SQL实现中,都有其他品牌不支持的各种语法功能或内置函数。

当我在Zend Framework的Zend::Db组件上工作时,我能给出的最好建议就是使用适配器模式。为每个想要支持的数据库创建一个子类,并在每个子类中以不同的方式实现每个功能。

Eloquent允许您开发更有意义的“构建器”方法,使基于模型的查询更加习惯化。 https://dev.to/rocksheep/cleaner-models-with-laravel-eloquent-builders-12h4

您将为每个品牌的数据库开发这些构建方法的单独实现。

2 年前
回复了 Bill Karwin 创建的主题 » mysql-C#在事务中抛出用户不退出例外

正如在上面的评论中所讨论的,错误来自一个触发器,该触发器在执行时试图采用其定义者的标识,但定义者('root'@')不再存在于MySQL实例上。

解决方法是创建该用户(即使您创建了该用户,然后禁用了身份验证)。

我们在我工作的地方这样做。我们使用具有超级权限的特殊用户定义触发器、存储过程和视图,尽管我们从未将该用户用于任何数据库访问。我们为应用程序和个人开发者创建其他MySQL用户,但不向这些用户授予超级权限。

2 年前
回复了 Bill Karwin 创建的主题 » MySQL分割单元值

https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_substring 说:

值为0表示 pos 返回一个空字符串。

换句话说,子字符串位置是基于1的,而不是基于0的。

2 年前
回复了 Bill Karwin 创建的主题 » 在mySQL中创建表时如何使用变量?

SQL语法和标识符必须在分析CREATE TABLE语句时固定。因此,不能使用变量或参数。

您可以创建一个字符串,插入变量,然后以动态SQL的形式准备和执行该字符串。

SET @myEnum= 'ENUM(''fulfilled'', ''noshow'', ''cancelled'')';

SET @ddl = CONCAT(
  'CREATE TABLE `Appointments` (
    `AppointmentID` VARCHAR(36) NOT NULL UNIQUE,
    `AppointmentFulfilled` ', @myEnum,
  ')'
);

PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
2 年前
回复了 Bill Karwin 创建的主题 » MySQL选择不同的值时工作不正常

您误解了DISTINCT在SQL中的工作方式。如果整行(即所有列)与结果中的任何其他行不同,则返回一行。这两行互不相同:

总的 sl_月 sl_年
9595 1. 二千零二十一
9595 2. 二千零二十一

从您描述的预期结果来看,您似乎想要 查询

SELECT gross, sl_month, sl_year
FROM (
 SELECT gross, sl_month, sl_year,
  ROW_NUMBER() OVER (PARTITION BY gross ORDER BY sl_year, sl_month) AS rownum
 FROM wp_attn_emp_salary 
 WHERE emp_id = 22
) AS t
WHERE t.rownum = 1
ORDER BY sl_month DESC, sl_year DESC;

注: Window functions 需要MYSQL 8.0,它于2018年发布,所以你现在应该已经在使用它了。如果您需要在早期版本的MySQL上运行的解决方案,请使用 标签

2 年前
回复了 Bill Karwin 创建的主题 » 如何在mysql视图中强制使用数据类型布尔

MySQL视图确实返回TINYINT,但只有在查询该类型的列时才返回。所有其他整数表达式都返回BIGINT。

我跑了 mysql --column-type-info 以获取有关结果的调试信息。

mysql> create table t ( b bool );

mysql> create or replace view v as select b from t;

mysql> select b from v;
Field   1:  `b`
Catalog:    `def`
Database:   `test2`
Table:      `v`
Org_table:  `v`
Type:       TINY
Collation:  binary (63)
Length:     1
Max_length: 0
Decimals:   0
Flags:      NUM 

mysql> select NOT b from v;
Field   1:  `NOT b`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       LONGLONG
Collation:  binary (63)
Length:     1
Max_length: 0
Decimals:   0
Flags:      BINARY NUM 

mysql> create or replace view v (b) as select NOT b from t;

mysql> select b from v;
Field   1:  `b`
Catalog:    `def`
Database:   ``
Table:      `v`
Org_table:  `v`
Type:       LONGLONG
Collation:  binary (63)
Length:     1
Max_length: 0
Decimals:   0
Flags:      BINARY NUM 
2 年前
回复了 Bill Karwin 创建的主题 » 如何在MySQL中连接多个表时只更新“最近”的记录

MySQL通常不喜欢在子查询中从表中选择并尝试在同一语句中更新它。

解决方法是连接到表,而不是在子查询中进行选择。我们正在寻找没有日期更大的匹配行的情况:

update ContactNote cn
    INNER JOIN Contact contact on contact.ContactId = cn.ContactId
    INNER JOIN ContactCategory contactCategory on contactCategory.ContactId = contact.ContactId
    INNER JOIN Category category on category.CategoryId = contactCategory.CategoryId
    LEFT OUTER JOIN ContactNote gt
        ON gt.ContactId = cn.ContactId AND gt.NodeDateTime > cn.NodeDateTime
SET cn.IsProspecting = b'1' 
WHERE contact.TeamId = 1
    AND contact.SpouseLastName = 'Rhodes'
    AND category.`Name` IN ('Sphere')
    AND gt.ContactId IS NULL -- meaning there is no note with a greater datetime
;

如果没有找到匹配的行,LEFT OUTER JOIN将为联接表的所有列返回NULL。如果条件试图查找具有更大NodeDateTime的注释,但未找到任何注释,则该行中的NodeDateTime cn 必须是相应CONTACT的最长(最近)日期时间。

这确实有一个缺点:如果最近一次有多张便笺?它将用更大的日期时间更新所有没有注释的注释,这可能会更新多个注释。这就是你想要的吗?

2 年前
回复了 Bill Karwin 创建的主题 » MySQL在更新新版本和旧版本之前触发

这个 <=> 操作员会测试空白值是否等于非空白值。

mysql> select '' <=> 'notblank' as same;
+------+
| same |
+------+
|    0 |
+------+
2 年前
回复了 Bill Karwin 创建的主题 » 如果列不存在,则绕过mysql错误

你有两个选择:

第一种解决方案:首先检查列是否存在。

SELECT t.table_name, (c.column_name IS NULL) AS columnA_present
FROM INFORMATION_SCHEMA.TABLES AS t
LEFT OUTER JOIN INFORMATION_SCHEMA.COLUMNS AS c
  ON t.table_name = c.table_name and c.column_name = 'columnA'
WHERE t.table_name = 'table1';

第二种解决方案:运行更新并捕获错误。检查错误是否为1054。如果是这样,那就跳过它。如果不是,那么是其他错误,所以报告它。

2 年前
回复了 Bill Karwin 创建的主题 » 在MySQL中使用REGEXP进行模式匹配

你描述了自己的情况:

如果字符串的第二到第三个位置完全匹配 07 .

这个 {2,3} 模式不需要用于此。你只需要检查文字字符 07 跟随第一个字符。

SELECT CASE WHEN 'a07ha' REGEXP '^.07' THEN '07' ELSE '00' END AS `group` 

上面的评论是在用答案取笑你。

请阅读MySQL上的手册 RAND() function :

...对于相等的参数值,RAND(N)每次返回相同的值,从而生成一个可重复的列值序列。在下面的示例中,RAND(3)生成的值序列在两个位置都是相同的。

由于CURDATE()在同一天内每次调用时都返回一个常量值,因此将其传递给RAND()会使RAND()在每次调用时都返回相同的值。

演示:

mysql> select rand(curdate());
+------------------+
| rand(curdate())  |
+------------------+
| 0.49455075570806 |
+------------------+
1 row in set (0.00 sec)

mysql> select rand(curdate());
+------------------+
| rand(curdate())  |
+------------------+
| 0.49455075570806 |
+------------------+
1 row in set (0.00 sec)

mysql> select rand(curdate());
+------------------+
| rand(curdate())  |
+------------------+
| 0.49455075570806 |
+------------------+
1 row in set (0.00 sec)

mysql> select rand(curdate());
+------------------+
| rand(curdate())  |
+------------------+
| 0.49455075570806 |
+------------------+
1 row in set (0.00 sec)

这将一直持续到我的时钟显示这是新的一天。

实际上不需要将值传递给seed RAND()。当MySQL服务器启动时,它会得到一个种子,并继续生成随机值。

当需要一系列新的随机值时,不要使用seed参数,当需要 可复制的随机值序列 ,例如,如果您正在运行自动测试。


请回复您的评论:

RAND()的参数是一个整数,但像“2021-11-07”这样的日期将作为字符串返回。在数值上下文中,“2021-11-07”的整数值为2021。任何非数字字符在作为参数传递给RAND()之前都会被去除。

mysql> select rand('2021-11-04');
+--------------------+
| rand('2021-11-04') |
+--------------------+
| 0.7752841103591808 |
+--------------------+
1 row in set, 1 warning (0.00 sec)

mysql> select rand('2021-11-05');
+--------------------+
| rand('2021-11-05') |
+--------------------+
| 0.7752841103591808 |
+--------------------+
1 row in set, 1 warning (0.00 sec)

mysql> select rand('2021-11-06');
+--------------------+
| rand('2021-11-06') |
+--------------------+
| 0.7752841103591808 |
+--------------------+
1 row in set, 1 warning (0.00 sec)

mysql> select rand('2021-11-07');
+--------------------+
| rand('2021-11-07') |
+--------------------+
| 0.7752841103591808 |
+--------------------+
1 row in set, 1 warning (0.00 sec)

你可以看到它是这样做的:

mysql> show warnings;
+---------+------+-------------------------------------------------+
| Level   | Code | Message                                         |
+---------+------+-------------------------------------------------+
| Warning | 1292 | Truncated incorrect INTEGER value: '2021-11-07' |
+---------+------+-------------------------------------------------+

所有这些日期都在播种随机数,好像你只通过了“2021”或2021作为参数:

mysql> select rand('2021');
+--------------------+
| rand('2021')       |
+--------------------+
| 0.7752841103591808 |
+--------------------+
1 row in set (0.00 sec)

mysql> select rand(2021);
+--------------------+
| rand(2021)         |
+--------------------+
| 0.7752841103591808 |
+--------------------+
1 row in set (0.00 sec)
4 年前
回复了 Bill Karwin 创建的主题 » 在mySQL中更改字符集时出错?

请在此处查看ALTER TABLE的语法: https://dev.mysql.com/doc/refman/5.6/en/alter-table.html

即使你不改名字。

ALTER TABLE contenidos CHANGE COLUMN titulo 
  titulo varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

ALTER TABLE contenidos CHANGE COLUMN <old_name> <new_name> <data-type> ...

CHANGE列的语法要求您提供两个名称,即使它们是相同的。

替代方法:使用MODIFY COLUMN,它不允许更改列名,但允许更改其他列属性,包括字符集。所以您只需要列出一次列名。

ALTER TABLE contenidos MODIFY COLUMN titulo 
  varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

ALTER TABLE contenidos MODIFY COLUMN titulo 
  varchar(500) COLLATE utf8mb4_general_ci;
5 年前
回复了 Bill Karwin 创建的主题 » 哪个JDBC连接器到MySQL8.0.15用户[重复]

“MySQL Connector/J”是JDBC驱动程序的产品名。

下载MySQL Connector/J并提取存档文件。你会找到文件的 mysql-connector-java-8.0.15.jar 在那个档案的顶层目录中。

Java是独立于平台的。我使用的是Macbook,我选择了独立于平台的存档。这意味着它是一个 tar zip 存档,而不是Linux或Windows的安装程序包。他们曾经提供MacOS安装程序,但似乎已经停止了。


DriverManager 接口。请参阅此处的示例代码: https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-usagenotes-connect-drivermanager.html#connector-j-examples-connection-drivermanager

在Java中,90%的问题是由类路径引起的。另外10%是由于气相色谱。

https://twitter.com/billkarwin/status/809491612434767872

5 年前
回复了 Bill Karwin 创建的主题 » 尽管语句在数据库中工作,PHP/MYSQL Select语句仍抛出错误

关于错误检查,我尝试了$q撸resultSel=$stmtSel->execute()或die(mysqli撸error($q撸resultSel));但它没有输出任何内容

当你检查错误时,你应该在 prepare() 以及 execute() ,因为每种情况下都会出现不同类型的错误。

当你发现错误时 准备() ,这意味着创建语句失败,因此必须从连接获取错误:

$stmtSel = $connSel -> prepare($sqlSel);
if ($stmtSel === false) {
    die($connSel->error);
}

当你发现错误时 执行() ,这意味着您有一个语句,但执行该语句失败。所以你必须从语句中得到错误:

$q_resultSel = $stmtSel -> execute();
if ($q_resultSel === false) {
    die($stmtSel->error);
}

另一种方法是启用mysqli异常,这样就不必编写任何代码来显式检查错误。如果有错误,它们将通过抛出异常来中断代码执行。

以下是如何启用异常:

$driver = new mysqli_driver();
$driver->report_mode = MYSQLI_REPORT_ALL;

阅读有关错误检查的文档:


我越看你的代码,我发现的错误就越多。

$q_resultSel = $stmtSel -> execute();

你应该看看 docs on the execute() function :

返回值

成功时返回TRUE,失败时返回FALSE。

请注意 执行() 不返回对象,当成功或有错误时返回布尔值。

那意味着 $q_resultSel->fetch_assoc() 即使查询没有问题,也会导致致命错误。使用它总是无效的 -> 关于PHP中的布尔值。

if(sizeof($q_resultSel)>0){

检查结果的大小是多余的。因为你唯一能做的就是 >0 就是运行一个 while 循环,你最好跳过 if 条件,因为如果结果有0行,则 虽然 无论如何,循环将立即终止。

while($row = $q_resultSel->fetch_assoc()){
    echo $row['username']."<br><br>".$row['comment'];
}

如前所述,您试图调用 $q_resultSel ,这一定是布尔值TRUE或FALSE。这就是致命错误的原因。

相反,您应该在调用 执行() 在确认 执行() 未返回FALSE指示错误:

$ok = $stmtSel -> execute();
if ($ok === false) {
    die($stmtSel->error);
}

$q_resultSel = $stmtSel->get_result();
if ($q_resultSel === false) {
    die($stmtSel->error);
}

while($row = $q_resultSel->fetch_assoc()){
    echo $row['username']."<br><br>".$row['comment'];
}

阅读有关获取结果的文档,并附带代码示例:

请注意 get_result() 是一个只有在PHP安装使用mysqlnd驱动程序时才能使用的函数。默认情况下,大多数现代PHP安装都应该这样做,但您可以通过在shell命令行获取PHP配置信息来进行检查:

php -i

... lots of output ...

mysqlnd

mysqlnd => enabled

... lots more output ...
4 年前
回复了 Bill Karwin 创建的主题 » 使用Alembic的存储过程:MySQL语法错误

你不需要 DELIMITER 除了在支持一系列分号分隔语句的环境中之外,MySQL客户端。

事实上 分隔符 命令是 mysql client builtin ,MySQL服务器无法识别。

你不能用 分隔符 当通过API向MySQL服务器提交语句时,即使 CREATE PROCEDURE .

5 年前
回复了 Bill Karwin 创建的主题 » 无法将mysql输出写入lcoal文件

这个 secure_file_priv 必须准确地命名输出到的目录。不能输出到子目录中。

下面是我刚刚在笔记本电脑上使用mysql 5.6的演示:

mysql> select @@global.secure_file_priv;
+---------------------------+
| @@global.secure_file_priv |
+---------------------------+
| /tmp/                     |
+---------------------------+

mysql> select 123 into outfile '/tmp/foo';
Query OK, 1 row affected (0.00 sec)

检查数据是否已写出:

$ cat /tmp/foo
123

然后尝试子目录:

mysql> select 456 into outfile '/tmp/a/b/text';
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

即使我 mkdir -p /tmp/a/b 为了确保在尝试这个子目录之前,它仍然失败。

4 年前
回复了 Bill Karwin 创建的主题 » 需要有关mysql查询[duplicate]的帮助

除了违反 First Normal Form 由于在单个列中存储了重复的值组,逗号分隔的列表还有许多其他更实际的问题:

  • 无法确保每个值都是正确的数据类型:无法防止 1,2,3,香蕉,5
  • 不能使用外键约束将值链接到查找表;无法强制引用完整性。
  • 无法强制唯一性:无法防止 1,2,3,3,3,5号
  • 无法在不获取整个列表的情况下从列表中删除值。
  • 不能存储比字符串列中的内容长的列表。
  • 很难搜索列表中具有给定值的所有实体;必须使用效率低下的表扫描。可能必须使用正则表达式,例如在mysql中:
    idlist REGEXP '[[:<:]]2[[:>:]]' *
  • 很难计算列表中的元素数,或者执行其他聚合查询。
  • 很难将值连接到它们引用的查找表。
  • 很难按顺序提取列表。

为了解决这些问题,您必须编写大量的应用程序代码,重新设计rdbms 已经提供了更有效的 是的。

逗号分隔的列表是错误的,我把它作为我书中的第一章: SQL Antipatterns: Avoiding the Pitfalls of Database Programming 是的。

有时需要使用非规范化,但是 @OMG Ponies mentions ,这些是例外情况。任何非关系优化都会以牺牲数据的其他用途为代价而使一种查询受益,因此请确保您知道哪些查询需要特别处理,以使它们值得非规范化。


* mysql 8.0不再支持这种单词边界表达式语法。

4 年前
回复了 Bill Karwin 创建的主题 » 在mysql行的100列中选择至少6个值

您似乎正在以非规范化的方式存储多值属性。

如果需要对这些值进行面向集的比较,它们应该存储在 ,而不是列。

您可以“取消激活”它们,因此每个值都在自己的行上,如下所示:

SELECT 1 AS ValNo, A1 AS Val FROM MyTable WHERE rowID=1
UNION ALL 
SELECT 2, A2 FROM MyTable WHERE rowID=1
UNION ALL
SELECT 3, A3 FROM MyTable WHERE rowID=1
UNION ALL
SELECT 4, A4 FROM MyTable WHERE rowID=1
UNION ALL
...
UNION ALL
SELECT 100, A100 FROM MyTable WHERE rowID=1

然后将其放入子查询中,得到最低的6个值。

SELECT ValNo, Val
FROM ( ... subquery above ... ) AS t
ORDER BY Val
LIMIT 6

最好存储一个表,其中一列是值,最多100 为每个人 rowId 以下内容:

CREATE TABLE MyNewTable (
  RowId INT,
  OrdinalId TINYINT, -- 1 to 100
  Aval INT,
  PRIMARY KEY (RowId, OrdinalId)
);

然后您可以更简单地查询它:

SELECT OrdinalId, Aval
FROM MyNewTable
WHERE RowId = 1
ORDER BY Aval
LIMIT 6;
5 年前
回复了 Bill Karwin 创建的主题 » 尝试在amazon aws的mysql数据库上使用json_对象函数

您可以用这个查询验证您的MySQL服务器版本:

SELECT VERSION();

如果使用json_object(),则结果将作为字符串返回到pdo,该字符串碰巧包含json格式的结果。

$stmt = $pdo->prepare("SELECT JSON_OBJECT('id', id, 'name', name, 'age', age) as doc FROM person");
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
var_dump($results);

输出:

array(1) {
  [0]=>
  array(1) {
    ["doc"]=>
    string(37) "{"id": 1, "age": 14, "name": "Harry"}"
  }
}

如果mysql不支持json_object(),则可以将常规结果集作为关联数组获取,然后使用类似json_encode()的php函数将该数组转换为json。

$stmt = $pdo->prepare("SELECT id, name, age FROM person");
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
$doc = json_encode($results);
echo $doc . "\n";

输出:

[{"id":"1","name":"Harry","age":"14"}]
5 年前
回复了 Bill Karwin 创建的主题 » 如何查看mysql dump的进程?

我是这样做的:

pv -pert abc.sql | mysql --defaults-file=/apps/mysql/instance/db01/my.cnf-UTIL

pv 是“通过管道监视数据进度”的Linux工具。

输出与 -pert 选项如下:

0:00:29 [1.98MiB/s] [===>                                     ] 10% ETA 0:03:54

作为 pv 命令读取文件并将其传递给 mysql ,进度条前进,时间更新,等等。真的很方便。

5 年前
回复了 Bill Karwin 创建的主题 » 如何创建主键不是自动递增的mysql

您只需要为auto inc列创建一个键(也称为索引)。它不必是主键,但必须是某个索引中最左边的列。

create table Cust (
  Name varchar(50), 
  Cat1 varchar(50), 
  RowID int NOT NULL AUTO_INCREMENT, 
  PRIMARY KEY (Name),
  KEY (RowId)
);

不要将唯一选项添加到“名称”列。这就创建了一个额外的多余的惟一索引,您不需要它。任何主键都已是唯一的。

我想说汽车公司和rowid不是一回事。不要指望汽车公司有连续的价值观。

5 年前
回复了 Bill Karwin 创建的主题 » mysql会根据多列索引顺序重新排序where条件吗?

是的,mysql的优化器可以看出 AND 是代数交换的,也就是说, A AND B 逻辑上与 B AND A .

它可以在保持逻辑等价性的情况下重新排序项以匹配索引顺序。

但是,在你展示的情况下, column1 是范围条件,因此MySQL无法使用索引在第二列中搜索。中的值 column2 是按第1列的值排序的,所以它们实际上没有顺序。在其中搜索行 column2 > 3 无论如何,必须搜索与第一个项匹配的每一行子集,到那时,存储引擎已经将这些行读入内存,因此使用索引没有什么价值。

6 年前
回复了 Bill Karwin 创建的主题 » 如何在mysql中创建只显示最后一行的组?[重复]

MySQL8.0现在支持窗口功能,就像几乎所有流行的SQL实现一样。使用此标准语法,我们可以编写每个组最多n个查询:

WITH ranked_messages AS (
  SELECT m.*, ROW_NUMBER() OVER (PARTITION BY name ORDER BY id DESC) AS rn
  FROM messages AS m
)
SELECT * FROM ranked_messages WHERE rn = 1;

以下是我在2009年为这个问题写的原始答案:


我这样写解决方案:

SELECT m1.*
FROM messages m1 LEFT JOIN messages m2
 ON (m1.name = m2.name AND m1.id < m2.id)
WHERE m2.id IS NULL;

在性能方面,根据数据的性质,一个或另一个解决方案可能更好。因此,您应该测试这两个查询,并使用在给定数据库的情况下性能更好的查询。

例如,我有一份 StackOverflow August data dump . 我会用它来做基准测试。共有1114357行 Posts 表。正在运行 MySQL 5.0.75在我的MacBook Pro 2.40GHz上。

我将编写一个查询来查找给定用户id(我的)的最新帖子。

第一次使用技术 shown 由@eric和 GROUP BY 在子查询中:

SELECT p1.postid
FROM Posts p1
INNER JOIN (SELECT pi.owneruserid, MAX(pi.postid) AS maxpostid
            FROM Posts pi GROUP BY pi.owneruserid) p2
  ON (p1.postid = p2.maxpostid)
WHERE p1.owneruserid = 20860;

1 row in set (1 min 17.89 sec)

即使是 EXPLAIN analysis 超过16秒:

+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
| id | select_type | table      | type   | possible_keys              | key         | key_len | ref          | rows    | Extra       |
+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL                       | NULL        | NULL    | NULL         |   76756 |             | 
|  1 | PRIMARY     | p1         | eq_ref | PRIMARY,PostId,OwnerUserId | PRIMARY     | 8       | p2.maxpostid |       1 | Using where | 
|  2 | DERIVED     | pi         | index  | NULL                       | OwnerUserId | 8       | NULL         | 1151268 | Using index | 
+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
3 rows in set (16.09 sec)

现在使用 my technique 具有 LEFT JOIN :

SELECT p1.postid
FROM Posts p1 LEFT JOIN posts p2
  ON (p1.owneruserid = p2.owneruserid AND p1.postid < p2.postid)
WHERE p2.postid IS NULL AND p1.owneruserid = 20860;

1 row in set (0.28 sec)

这个 解释 分析表明,这两个表都可以使用其索引:

+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
| id | select_type | table | type | possible_keys              | key         | key_len | ref   | rows | Extra                                |
+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
|  1 | SIMPLE      | p1    | ref  | OwnerUserId                | OwnerUserId | 8       | const | 1384 | Using index                          | 
|  1 | SIMPLE      | p2    | ref  | PRIMARY,PostId,OwnerUserId | OwnerUserId | 8       | const | 1384 | Using where; Using index; Not exists | 
+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
2 rows in set (0.00 sec)

这是我的DDL 帖子 表:

CREATE TABLE `posts` (
  `PostId` bigint(20) unsigned NOT NULL auto_increment,
  `PostTypeId` bigint(20) unsigned NOT NULL,
  `AcceptedAnswerId` bigint(20) unsigned default NULL,
  `ParentId` bigint(20) unsigned default NULL,
  `CreationDate` datetime NOT NULL,
  `Score` int(11) NOT NULL default '0',
  `ViewCount` int(11) NOT NULL default '0',
  `Body` text NOT NULL,
  `OwnerUserId` bigint(20) unsigned NOT NULL,
  `OwnerDisplayName` varchar(40) default NULL,
  `LastEditorUserId` bigint(20) unsigned default NULL,
  `LastEditDate` datetime default NULL,
  `LastActivityDate` datetime default NULL,
  `Title` varchar(250) NOT NULL default '',
  `Tags` varchar(150) NOT NULL default '',
  `AnswerCount` int(11) NOT NULL default '0',
  `CommentCount` int(11) NOT NULL default '0',
  `FavoriteCount` int(11) NOT NULL default '0',
  `ClosedDate` datetime default NULL,
  PRIMARY KEY  (`PostId`),
  UNIQUE KEY `PostId` (`PostId`),
  KEY `PostTypeId` (`PostTypeId`),
  KEY `AcceptedAnswerId` (`AcceptedAnswerId`),
  KEY `OwnerUserId` (`OwnerUserId`),
  KEY `LastEditorUserId` (`LastEditorUserId`),
  KEY `ParentId` (`ParentId`),
  CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`PostTypeId`) REFERENCES `posttypes` (`PostTypeId`)
) ENGINE=InnoDB;
5 年前
回复了 Bill Karwin 创建的主题 » 如何从programdata文件恢复mysql innodb数据库

问题是文件的所有权和权限。

mysql datadir下的文件必须可由mysqld进程的uid读取和写入。这通常是一个uid“mysql”(因为很多年前大家都同意将守护进程作为根目录运行不是一个好主意)。在默认安装中还有一个gid“mysql”。

因此,解决办法是:

chown -R mysql:mysql <datadir>
4 年前
回复了 Bill Karwin 创建的主题 » mysql错误(hy000):无法添加外键约束

https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html 说:

如果指定了set null操作,请确保没有将子表中的列声明为not null。

但是你 purchase_item.product_id 列是该表的主键的一部分,它隐式地使该列不为空。

您不能使用 SET NULL 该列上的主键的操作。

5 年前
回复了 Bill Karwin 创建的主题 » 更改php/mysql数据库会创建不安全的连接吗?

最好将数据库凭据与代码分开。为了防止有人找到读取您代码的方法,他们不应该看到您的数据库密码。

将数据库凭据保存在配置文件中,应用程序在启动时读取该文件。我会用 parse_ini_file() .

下面是一个配置文件示例:

[database]
host=localhost
user=imauser
password=imapassword
dbname=liveDB

以下是您的阅读方式:

$config = parse_ini_file('config.ini', true);

如果我输出 print_r($config) 我看到了:

Array
(
    [database] => Array
        (
            [host] => localhost
            [user] => imauser
            [password] => imapassword
            [dbname] => liveDB
        )

)

这样,您就可以在测试和生产环境中部署相同的代码,并且只需要替换测试和生产服务器中的配置文件。

注意:请确保不要将配置文件放在Web服务器可以提供文件的目录下。您的PHP代码可以从服务器上的任何地方读取文件,因此请确保没有人可以在浏览器中简单地打开配置文件。