【Golang】sql.Null* 类型使用(处理空值和零值)

 sql.NullStringsql.NullInt64 类型(以及其他类似的 sql.Null* 类型)在处理数据库操作时非常有用,尤其是在 Go 语言的 database/sql 包中。它们的主要用途包括:

  1. 表示 NULL 值

    • 在数据库中,NULL 表示“没有值”。sql.Null* 类型允许你在 Go 语言中直接表示和处理这种“没有值”的状态,而不是使用 Go 的零值(如空字符串 "" 或整数 0)来表示 NULL,这样可以更准确地反映数据库中的数据状态。
  2. 数据库交互

    • 当你从数据库查询数据时,某些字段可能是 NULL。使用 sql.Null* 类型可以区分一个字段是真正包含零值还是 NULL。这对于后续的逻辑处理非常重要,因为零值和 NULL 在逻辑上可能有不同的含义。
  3. 避免错误

    • 如果不使用 sql.Null* 类型,你可能会错误地将数据库中的 NULL 值解释为 Go 语言中的零值,这可能导致逻辑错误或程序崩溃。
  4. 简化代码

    • 使用 sql.Null* 类型可以简化代码,因为你不需要编写额外的检查来确定一个值是否来自数据库中的 NULL。Valid 字段可以直接告诉你这个值是否有效。
  5. 数据完整性

    • 在将数据写入数据库时,sql.Null* 类型可以帮助你保持数据的完整性。你可以准确地标记哪些字段是有意设置为 NULL,哪些字段是具有实际值的。
  6. 灵活性

    • sql.Null* 类型提供了灵活性,允许你在不改变现有代码结构的情况下,处理那些可能为 NULL 的字段。

示例场景:

假设你正在处理一个用户信息表,其中有一个字段表示用户的出生日期。在某些情况下,用户可能没有提供出生日期,因此这个字段在数据库中是 NULL。使用 sql.NullStringsql.NullInt64(取决于出生日期如何存储)可以让你在 Go 程序中准确地表示这种情况,并在需要时进行适当的处理。

package mainimport ("database/sql""fmt"
)// DbBackedUser 用户结构体,由数据库支持
type DbBackedUser struct {Name sql.NullStringAge  sql.NullInt64
}func main() {// 空值var name sql.NullStringx := DbBackedUser{Name: name, Age: sql.NullInt64{Int64: 0, Valid: false}}// 输出结果fmt.Println("Name:")fmt.Println("String:", x.Name.String) // 输出: ""fmt.Println("Valid:", x.Name.Valid)   // 输出: falsefmt.Println("Age:")fmt.Println("Int64:", x.Age.Int64)  // 输出: 0fmt.Println("Valid:", x.Age.Valid)   // 输出: false
}
Name:
String: 
Valid: false
Age:
Int64: 0
Valid: false

加入与数据库交互

1. 创建测试表

clickhouse-client

首先,我们需要在 ClickHouse 中创建一个测试表。因为你的数据结构包含 NameAge,我们可以使用以下 SQL 语句创建表: 

CREATE TABLE test_table
(`Name` Nullable(String),`Age`  Nullable(Int64)
) ENGINE = Memory;

2. 插入数据

接下来,我们插入一些数据,包括空值和零值:

INSERT INTO test_table VALUES ('Kimi', 30), ('', 0), (NULL, NULL);

这里,我们插入了三行数据:

  • 第一行:Name 是 "Kimi",Age 是 30。
  • 第二行:Name 是空字符串,Age 是 0。
  • 第三行:Name 和 Age 都是 NULL。

3. 查询数据

查询表中的所有数据:

SELECT * FROM test_table;

package mainimport ("database/sql""fmt""log"_ "github.com/ClickHouse/clickhouse-go"
)// DbBackedUser 用户结构体,由数据库支持
type DbBackedUser struct {Name sql.NullStringAge  sql.NullInt64
}func main() {// 连接到 ClickHouse 数据库connStr := "tcp://localhost:9000?username=default&password=&database=default"db, err := sql.Open("clickhouse", connStr)if err != nil {log.Fatal(err)}defer db.Close()// 查询并打印现有的数据fmt.Println("Query results before insertion:")queryData(db)fmt.Println("查询并打印现有的数据")// 开始事务tx, err := db.Begin()if err != nil {log.Fatal(err)}// 空值var name sql.NullStringx := DbBackedUser{Name: name, Age: sql.NullInt64{Int64: 1, Valid: false}}// 插入数据_, err = tx.Exec("INSERT INTO test_table2 (Name, Age) VALUES (?, ?)", x.Name, x.Age)if err != nil {tx.Rollback() // 如果出现错误,回滚事务log.Fatal(err)}// 提交事务err = tx.Commit()if err != nil {log.Fatal(err)}// 查询并打印插入后的数据fmt.Println("Query results after insertion:")queryData(db)fmt.Println("查询并打印现有的数据")}func queryData(db *sql.DB) {rows, err := db.Query("SELECT Name, Age FROM test_table2")if err != nil {log.Fatal(err)}defer rows.Close()var nameValue sql.NullStringvar ageValue sql.NullInt64for rows.Next() {if err := rows.Scan(&nameValue, &ageValue); err != nil {log.Fatal(err)}fmt.Printf("name: %v, Age: %v\n", nameValue.String, ageValue.Int64)}
}

结果

这里

给数据库传了0值

改成true后

传值成功

NameValid改成false

传null

package mainimport ("database/sql""fmt""reflect""github.com/go-playground/validator/v10"
)// DbBackedUser 用户结构体,由数据库支持
type DbBackedUser struct {Name sql.NullString `validate:"required"` // 可以为NULL的字符串,验证规则为必填Age  sql.NullInt64  `validate:"required"` // 可以为NULL的整数,验证规则为必填
}// 使用单一实例的验证器,它缓存结构体信息
var validate *validator.Validatefunc main() {// 创建一个新的验证器实例validate = validator.New()// 注册所有sql.Null*类型,使用自定义的ValidateValuer函数validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{})// 构建对象进行验证// Name字段为空字符串但Valid为true,表示非NULL;Age字段为0且Valid为false,表示NULLx := DbBackedUser{Name: sql.NullString{String: "zahngsan", Valid: true}, Age: sql.NullInt64{Int64: 18, Valid: false}}// 对x进行结构体验证err := validate.Struct(x)// 如果验证失败,打印错误信息if err != nil {fmt.Printf("Err(s):\n%+v\n", err)}
}// ValidateValuer实现了validator.CustomTypeFunc接口
func ValidateValuer(field reflect.Value) interface{} {// 检查field是否为nilif !field.IsValid() {return nil}// 检查field是否实现了sql.Null*类型if nullType, ok := field.Interface().(sql.NullString); ok {// 如果Valid为true,返回字符串和非NULL的指示if nullType.Valid {fmt.Println("NullString Valid为true:",nullType.String)return []interface{}{nullType.String, true}}// 如果Valid为false,返回空字符串和NULL的指示fmt.Println("NullString Valid为false")return []interface{}{"", false}}// 检查field是否实现了sql.NullInt64类型if nullInt64, ok := field.Interface().(sql.NullInt64); ok {if nullInt64.Valid {fmt.Println("NullInt64 Valid为true:",nullInt64.Int64)return []interface{}{nullInt64.Int64,true}}fmt.Println("NullInt64 Valid为false")return []interface{}{"", false}}// 对其他sql.Null*类型进行类似的处理...// ...// 如果不是sql.Null*类型,返回nilreturn nil
}

结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/59614.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML 鼠标滑动 页面的header背景从透明色变为黑色

要实现当鼠标滑动时&#xff0c;页面的header背景从透明色变为黑色&#xff0c;你可以使用JavaScript来监听滚动事件&#xff0c;并根据页面的滚动位置来改变header的背景颜色。 <!DOCTYPE html> <html lang"en"> <head> <meta charset"U…

【前端】如何在 JSX 中使用条件语句和循环

在 JSX 中使用条件语句和循环是常见的需求&#xff0c;尤其是在构建动态用户界面时。以下是如何在 JSX 中使用条件语句和循环的详细说明。 条件语句 1. 三元运算符 三元运算符是最简单的条件语句形式&#xff0c;适用于简单的条件判断。 const isLoggedIn true;const ele…

Scala 的访问权限

1.1 Scala的访问权限概述 Scala中的属性成员、方法和构造器这三种变量可以通过访问控制符控制访问权限。不同的访问控制符可以决定是否可以被外部类访问。由于局部方法的作用域本身有局限&#xff0c;所以不需要使用访问控制符修饰局部方法。属性成员、方法和构造器的访问控制权…

标准化和归一化

标准化和归一化的概念 **标准化&#xff08;Standardization&#xff09;和归一化&#xff08;Normalization&#xff09;**是两种常见的数据预处理方法&#xff0c;旨在将特征数据转换为具有某种标准尺度的格式&#xff0c;以帮助模型更有效地学习。 1. 标准化&#xff08;S…

Rust移动开发:Rust在Android端集成使用介绍

Andorid调用Rust 目前Rust在移动端上的应用&#xff0c;一般作为应用sdk的提供&#xff0c;供各端使用&#xff0c;目前飞书底层使用Rust编写通用组件。 该篇适合对Android、Rust了解&#xff0c;想看如何做整合&#xff0c;如果想要工程源码&#xff0c;可以评论或留言有解疑…

UE hard/soft reference| DDX DDY | Unity pcg color

目录 1.虚幻引擎性能优化 &#xff08;附0跳转Unity对应机制&#xff09; hard reference and soft reference 1. 硬引用&#xff08;Hard Reference&#xff09; 2. 软引用&#xff08;Soft Reference&#xff09; 3. 使用原则 2.空间梯度转法线 DDX DDY节点 ​编辑 …

嵌入式开发之静态库和共享库

静态库 静态库的特点: 默认执行库链接的时候,检索的是Linux的/lib、/usr/lib目录下,如果指定gcc -c .... -L 指定路径 -l指定库文件;c语言分为预编译、编译、汇编、链接四个步骤。链接的时候是把依赖库文件函数的代码拷贝到程序里面,即便是删除库文件。拷贝后的程序依旧…

【UE5】一种老派的假反射做法,可以用于移动端,或对反射的速度、清晰度有需求的地方

没想到大家这篇文章呼声还挺高 这篇文章是对它的详细实现&#xff0c;建议在阅读本篇之前&#xff0c;先浏览一下前面的文章&#xff0c;以便更好地理解和掌握内容。 这种老派的假反射技术&#xff0c;适合用于移动端或对反射效果的速度和清晰度有较高要求的场合。该技术通过一…

前端学习Day12 CSS盒子的定位(相对定位篇“附练习”)

一、相对定位 使用相对定位的盒子会相对于自身原本的位置&#xff0c;通过偏移指定的距离&#xff0c;到达新的位置。盒子的本体仍处于文档流中。使用相对定位&#xff0c;除了要将 position 属性值设置为 relative 外&#xff0c;还需要指定一定的偏移量。其中&#xff0c;水…

【ChatGPT】让ChatGPT生成跨语言翻译的精确提示

让ChatGPT生成跨语言翻译的精确提示 在跨语言交流中&#xff0c;为了确保翻译的准确性&#xff0c;生成精确的提示&#xff08;Prompt&#xff09;来指导ChatGPT翻译内容是至关重要的。无论是要处理复杂的技术术语、俚语&#xff0c;还是保持特定的语言风格&#xff0c;使用有…

PostgreSQL 页文件损坏

PostgreSQL 提示 ERROR: missing chunk number 0 for toast value 32789 in pg_toast_2619 现象&#xff1a;查询业务表数据提示 ERROR: missing chunk number 0 for toast value 32789 in pg_toast_2619 处理方法&#xff1a;定位到损坏的行的位置&#xff0c;然后删除有问…

基于微信小程序的移动学习平台的设计与实现+ssm(lw+演示+源码+运行)

摘 要 由于APP软件在开发以及运营上面所需成本较高&#xff0c;而用户手机需要安装各种APP软件&#xff0c;因此占用用户过多的手机存储空间&#xff0c;导致用户手机运行缓慢&#xff0c;体验度比较差&#xff0c;进而导致用户会卸载非必要的APP&#xff0c;倒逼管理者必须改…

git 工具原理

git 目录 git git的使用 了解git的三个区域 具体操作 如何下载别人上传到git的工程 -- 可以参考菜鸟教程&#xff0c;包括安装配置git Git 安装配置 | 菜鸟教程 -- Git 是一种分布式版本控制系统&#xff0c;用于管理软件项目的源代码。它是由 Linux 之父 Linus Torval…

VLAN高级+以太网安全

VLAN聚合 MUX VLAN QinQ 以下是这三种VLAN技术的作用及其在项目中的应用实例&#xff1a; VLAN聚合 (VLAN Aggregation) VLAN聚合通常用于将多个VLAN数据聚合到一个物理链路上&#xff0c;以减少链路数量、提高链路利用率。这样可以在一个物理链路上同时传输不同VLAN的数据包&…

前端零基础学习Day-Six

CSS选择器 标签选择器 以HTML标签作为选择器&#xff1a; <style type"text/css"> p,h1,h2,h3,h4{font-size:30px;} p{color:blue;font-family:"隶书";} h1{color:red;} </style> 通过标签选择器设置样式&#xff0c;那使用该标签的内容都引…

springboot集成opencv开源计算机视觉库

最近项目需要用到opencv&#xff0c;网上看到很多资料都是下载安装并且引入jar包与dll文件&#xff0c;感觉很麻烦&#xff0c;不是我想要的&#xff0c;于是花时间折腾了下&#xff0c;不需要任何安装与引入jar包与dll文件&#xff0c;简单方便&#xff0c;快速上手。 先说说…

electron 中 webFrame 作用

1. 理解 Electron 中的 Web 内容呈现 在 Electron 应用中&#xff0c;渲染进程主要负责加载和呈现网页内容&#xff0c;这部分功能与浏览器中的标签页类似。 WebFrame 是 Electron 提供的一个模块&#xff0c;它在**管理和控制这些网页内容的呈现方面**发挥着关键作用。 2. …

Linux操作系统:学习进程_对进程的深入了解

目录 前言 开篇 一、进程概念 二、进程的描述与管理 1、如何描述与管理 2、Linux中的PCB-task_struct 3、对进程组织的理解 三、进程的属性 1、系统创建进程 2、查看进程 3、进程的标识符 4、退出进程 1>ctrlc 2>kill命令杀死进程 5、用户进程的创建方式…

Redis的缓存问题与应对策略

Redis 作为一种高效的缓存系统&#xff0c;在高并发环境下应用广泛&#xff0c;但也面临一些缓存问题&#xff0c;以下是常见问题及其应对策略。 1. 缓存穿透 问题描述 缓存穿透是指请求的数据在缓存和数据库中都不存在&#xff0c;但大量请求直接到达数据库&#xff0c;从而给…

虚拟户分账:电商资金管理的新曙光。

随着电商行业的蓬勃发展&#xff0c;资金管理成为了企业运营的重中之重。传统资金结算方式在面对大规模交易、复杂业务场景时&#xff0c;显得力不从心。在此背景下&#xff0c;电商虚拟户分账系统以其独特的优势&#xff0c;为电商企业带来了资金管理的新曙光。 电商虚拟户分…