SQL 外键名称问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL 外键名称问题相关的知识,希望对你有一定的参考价值。
什么是外键,如果有AB两个个表.B表中的字段引用了A表中的主键,那么这个主键是B表外键对吗?另外就是B表引用的字段名称要和A表主键一样吗?俩表的主键要一样吗?
我就以 班级表 与 学生表 来举例吧, 班级表好比A 学生表好比B.班级表 ( 班级ID, 班级名称, 班级其他信息...... ) 主键是 班级ID
学生表 (学号, 所属班级ID, 姓名,性别 ...... ) 主键是 学号, 外键是 所属班级ID
学生表的 外键的字段名称, 可以与 班级表的 主键列的字段名称不一样。
例如上面的, 班级表里面, 字段名称是 “班级ID”。 学生表里面, 字段名次是“所属班级ID”
名称可以不同, 但是数据类型要一样。
至于 这个学生表里面, 主键是 仅仅 “学号”。 还是 (“学号”, “所属班级ID”)
一般情况下, 比较单纯的 一对多的情况下, 学生表的主键, 一个学号就足够了, 不需要带上“所属班级ID”。
对于 “多对多”的情况下, 才需要把外键作为主键。
例如:
学生表 (学号, 所属班级ID, 姓名,性别 ...... ) 主键是 学号
课程表(课程编号, 课程名, 学分 ......) 主键是 课程编号
学生选修情况表 (学号, 课程编号) 主键是 (学号, 课程编号) 2个外键,学号依赖学生表, 课程编号依赖课程表 参考技术A 对,引用字段称为外健,B表字段引用了A表,这个字段就叫外健,可建关健约束追问
B表中的字段引用了A表的主键,那么A表的主键,一定要在B表中也出现或者充当主键吗?还是只需要指向一个主键就可以?
追答只要是唯一列,就可以被引用,不一定非是主健,你在A表建唯一约束的,其它表就可以引用
参考技术B AB两表主键不同,但B表的外键一定是A表的主键,B表的字段,字段类型一定和A表的字段,字段类型一致 参考技术C 很多人用powerdesigner设计数据库,都喜欢直接使用默认生成的主外键名称,我也是不太注意这个外键的名称,默认都是这样的FK_relation_XX,通常这个XX是一个数字;由于业务的变化和数据库的多次调整;这个数字本身就没有什么意义,如果对数据库的修改并不是每次修改都从设计文件开始修改然后在数据库建立同样名称的字段和外键,那时间久了一定会出现外键名字数据库和设计文件对不上的情况,后面再对数据的结构做调整就会显得冲突越来越多了 如果一开始就将外键的名称使用人工编辑的方式编辑为有意义的名称,就可以降低自动生成外键名称引起冲突的几率,也使数据库抛出外键异常的时候就直接可以根据外键约束的名称判断出是哪个表之间的问题。 看来还是那句话,慢工出细活,这种细都是有实际意义的细节,而不是锦上添花的东西。控制器不断生成带有错误外键名称的 SQL 查询
【中文标题】控制器不断生成带有错误外键名称的 SQL 查询【英文标题】:Controller keeps generating SQL query with wrong foreign key name 【发布时间】:2019-12-15 05:28:00 【问题描述】:我有一个数据库表用户,列表 用户表:
id, name, email, password
列表表:
id, title, seller_id
列表迁移:
public function up()
Schema::create('listings', function (Blueprint $table)
$table->bigIncrements('id');
$table->string('title');
$table->bigInteger('seller_id')->unsigned();
$table->timestamps();
$table->foreign('seller_id')->references('id')->on('users')->onDelete('cascade');
);
用户模型:
public function listings()
return $this->hasMany(Listing::class);
上市模式:
public function seller()
return $this->belongsTo(User::class, 'seller_id', 'id');
列表资源:
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ListingResource extends JsonResource
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
return parent::toArray($request);
列表控制器:
public function index()
return ListingResource::collection(auth()->user()->listings()->latest());
我不断收到此错误:
“SQLSTATE[42S22]: 找不到列: 1054 'where 子句'中的未知列'listings.user_id' (SQL: select * from listings
where listings
.user_id
= 1 和listings
。 user_id
is not null order by created_at
desc limit 1)"
即使我在 User.php 模型中专门将 'seller_id' 作为外键,它为什么会返回以 user_id 作为外键的查询?
我已经试过了:
public function listings()
return $this->hasMany(Listing::class, 'seller_id');
据我所知,这可以工作,但这会产生以下错误:
"调用未定义的方法 Illuminate\Database\Eloquent\Relations\HasMany::mapInto()"
【问题讨论】:
查看这篇文章以了解您的最后一个错误***.com/questions/47710805/… 如果你这样做auth()->user()->listings()->latest()->get()
是否有效? ->latest()
实际上并不执行查询;它是->orderBy('created_at', 'desc')
的简写,所以此时你有一个Builder
实例而不是Collection
。
@TimLwis 拍摄。我错过了那个小细节。这为我解决了这个问题。非常感谢!
【参考方案1】:
虽然错误消息对此不是最清楚的,但实际上发生的是 Resource::collection($collection);
需要 Collection
才能运行,但在其生命周期的当前点,您的参数是 Builder
实例.要解决此问题,只需传递 closure
即可将您的 Builder
转换为 Collection
:
public function index()
return ListingResource::collection(auth()->user()->listings()->latest()->get());
->latest()
是->orderBy('created_at', 'DESC');
(或id
,不确定它在内部使用哪个)的简写,但实际上并不执行查询。只需添加 ->get()
即可将 Builder
转换为 Collection
并允许此资源工作。
另一方面,原始错误是由于在您的listings()
模型上的listings()
函数中缺少seller_id
引起的。 Laravel 根据模型名称猜测任何关系的外部 id(User
转换为 user_id
),但由于您使用的是 seller_id
,因此您需要在原始关系和反向关系中都指定它定义。你想通了,但快速解释总是有帮助的。
【讨论】:
以上是关于SQL 外键名称问题的主要内容,如果未能解决你的问题,请参考以下文章