无需言 做自己 业 ,精于勤 荒于嬉.

前端开发 npm install 报错 解决 RequestError: certificate has expired

发表日期:2024-03-26 17:19:00 | 来源: | 分类:前端开发

      示例1
npm config set disturl https://registry.npmmirror.com/dist/
npm config set registry https://registry.npmmirror.com
npm config set electron_mirror https://npmmirror.com/mirrors/electron/
npm config set strict-ssl false
npm cache clean --force
npm install

阅读全文 »

Linux实战应用 解决 wsl 系统删除文件磁盘空间未得到释放

发表日期:2024-03-25 21:41:14 | 来源: | 分类:Linux实战应用

wsl 同虚拟机一样有此问题

1.先关闭wsl的Linux系统:

wsl --shutdown

2.打开磁盘收缩工具 ,cmd输入命令:

diskpart

3.先找到你的wsl系统的虚拟磁盘文件ext4.vhdx ,在diskpart 窗口里输入

select vdisk file="‪C:\Users\eniac\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu_79rhkp1fndgsc\LocalState\ext4.vhdx"

4.然后输入收缩命令,等待至100%收缩完成:

compact vdisk 

5.最后卸载虚拟磁盘:

detach vdisk


阅读全文 »

Linux实战应用 Linux服务器免费高效的安全软件

发表日期:2023-12-17 21:57:29 | 来源: | 分类:Linux实战应用

  • ClamAV:ClamAV是一款开源的防病毒引擎,用于检测木马、病毒、恶意软件和其他威胁。它支持多种平台,包括Linux,并且具有命令行和图形用户界面。

  • Fail2ban:Fail2ban是一个用于监控日志文件并自动封禁恶意IP地址的工具。它可以防止暴力破解和其他恶意行为。

  • SELinux:SELinux(Security-Enhanced Linux)是一个为Linux内核提供强制访问控制机制的安全模块。它可以限制进程和用户对系统资源的访问,从而增强系统的安全性。

  • AppArmor:AppArmor是一个Linux内核的安全模块,类似于SELinux,提供强制访问控制机制来保护应用程序和系统文件。

  • OpenSSH:OpenSSH是一个安全的远程登录工具,支持加密通信和身份验证。它可以帮助您在远程服务器上执行命令和管理任务。

  • Snort:Snort是一个开源的网络入侵检测和防御系统(IDS/IPS)。它可以实时监控网络流量,检测异常行为并生成警报。

  • OSSEC:OSSEC是一个开源的主机入侵检测系统(HIDS)。它可以监控系统日志、文件更改、进程活动等,以检测潜在的入侵行为。

  • UFW (Uncomplicated Firewall): UFW是一个用户友好的前端防火墙配置工具,旨在简化iptables防火墙规则的管理。它可以轻松地启用/禁用端口和服务,并管理网络流量。

  • ModSecurity: 这是一个开源的Web应用防火墙(WAF),用于保护Web应用程序免受各种攻击,如SQL注入、跨站脚本(XSS)等。

  • Lynis: Lynis是一个系统安全审计工具。它可以在不安装额外软件的情况下对系统进行全面的安全扫描,并提供加固建议。

  • AIDE (Advanced Intrusion Detection Environment): AIDE是一个用于检测文件系统完整性的工具,可帮助检测未经授权的文件修改或添加。

  • rkhunter (Rootkit Hunter): rkhunter是一个Unix平台的系统工具,用于扫描潜在的rootkit和其他恶意软件。

  • Tiger: Tiger是一个安全工具,用于收集和分析Linux系统上的安全相关信息,如系统日志、网络状态、已安装的软件等。

  • Chkrootkit: 类似于rkhunter,Chkrootkit也是一个用于检测rootkit和其他潜在恶意软件的工具。

  • DenyHosts: 这是一个Python程序,设计用于自动阻止SSH的暴力攻击。当发现过多的认证失败尝试时,它会更新/etc/hosts.deny来阻止攻击源。

  • John the Ripper & Hashcat: 这两个工具都是用于密码破解的,可以帮助测试系统的密码强度。

  • Key-based Authentication for SSH: 虽然不是软件,但使用SSH密钥进行身份验证是一种增强安全性的方法,可以避免使用弱密码。

阅读全文 »

Linux实战应用 Virtualbox虚拟机磁盘收缩

发表日期:2023-11-13 00:57:42 | 来源: | 分类:Linux实战应用

当你的虚拟机磁盘是动态大小时,不知你是否发现当你把虚拟机里的文件删除时,虚拟机磁盘可用空间变大了,而宿主机的磁盘可用空间并没有变大?那么也就是说虚拟机里曾经删除的文件其实还在占用你的磁盘空间。

原因是虚拟机里删除文件其实只是文件的状态被标注了删除,对于宿主机来说磁盘内容并没有删除。其实通俗来讲我们从电脑中删除文件都只是标注文件的删除状态,数据任然在磁盘只是不让你看到了,当写入数据时其实相当于“覆盖被删除的文件所占用的磁盘空间”。

以Linux虚拟机为例:

1. 就是创造一个空文件把磁盘写满(覆盖被删除的文件=清空磁盘空闲内容)执行命令:

dd if=/dev/zero of=temp

2.把这个文件删了

rm -f temp

3.关闭虚拟机,在宿主机系统中进入虚拟机软件安装目录执行命令:

C:\Program Files\Oracle\VirtualBox> .\VBoxManage.exe modifyvdi "D:\你要收缩的虚拟磁盘.vdi" --compact

等待结果:0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

执行完成后你会发现虚拟磁盘变小了。


如果你的宿主机磁盘够用,那么其实你可以不用管它。比如你设置的虚拟磁盘大小限制为100G,那么宿主机虚拟磁盘大小到100G时将不再增长,只要虚拟磁盘里空间没满,那么再写入的数据就是覆盖删除文件的空间了。

阅读全文 »

Linux实战应用 crontab 定时任务

发表日期:2023-05-31 09:48:06 | 来源: | 分类:Linux实战应用

      示例1
crontab -e
# 编辑定时任务  输入i 进入编辑模式

45 0 * * * /home/test.sh  > /dev/null
# 例如  每天0点45分 执行shell脚本

00 02 * * * rm -rf /home/canquick/cache/*
# 例如 每天2点 删除/home/canquick/cache/ 下的所有文件

* * * * * curl http://xxx/api.json
# 每分钟请求一次接口


* * * * * php /home/canquick/run.php
# 每分钟执行一次php脚本



#保存并退出 先按一下 ESC键  然后输入:wq 回车 ,和vim命令一样

阅读全文 »

Linux实战应用 FTP服务器软件 pureftpd 创建/删除用户

发表日期:2023-05-31 09:32:37 | 来源: | 分类:Linux实战应用

      示例1
pureftpd  创建用户:

#创建ftp项目目录
mkdir /home/wwwroot/test2/

#创建 test2FTP 用户  目录为 /home/wwwroot/test2/
echo "test2FTP:$6$bk3nSL0iiqvTM6t0$UxciEqn1zSd5fkTD4XIDI9nRsRu5a8LOukv19oSUaDMHr4BxWCG81UilttNAloPGOwmL/7gIb8WoLl.N8fD0z/:1001:1001::/home/wwwroot/test2/./::::::::::::" >> /usr/local/pureftpd/etc/pureftpd.passwd
# 实际上 是给 /usr/local/pureftpd/etc/pureftpd.passwd 文件插入一行,
# 也可以vim /usr/local/pureftpd/etc/pureftpd.passwd  复制插入上一行的用户数据 把用户名和 目录地址改为新的也行


#保存设置
/usr/local/pureftpd/bin/pure-pw mkdb

#给test2FTP设置密码 ,输入两遍密码
/usr/local/pureftpd/bin/pure-pw passwd test2FTP

#保持设置
/usr/local/pureftpd/bin/pure-pw mkdb

#然后即可以用FTP软件登录
#如果上传文件提示没权限 那么ll 命令查看一下项目目录的组和所有者是否是root
#如果是root那么把组和所有者改为网站访问的用户 如www即可
#chgrp www /home/wwwroot/test2/ 修改文件夹所有者
#chown www /home/wwwroot/test2/修改文件夹用户组

阅读全文 »

SQLServer 触发器详解

发表日期:2022-10-19 11:20:47 | 来源: | 分类:SQLServer

      示例1
create TRIGGER [dbo].[trigger_House(触发器的名字)]
    ON [dbo].[House(监听的表名)]
    AFTER INSERT, UPDATE -- 插入/修改后触发 ,delete 删除后触发
    AS
    BEGIN

        SET NOCOUNT ON;
        -- 你的业务逻辑 
        update House set modify_microtime = getdate() where HID in (select HID from inserted);
        
        -- 注意这句非常重要 where HID in (select HID from inserted) 查找更新的记录行
        -- 如果House表一次更新的是多行,那么触发的inserted 表也是多行,所以这里用了where in 而不是 =

    END
      示例2
drop trigger 触发器名字

阅读全文 »

SQLServer 自定义函数详解

发表日期:2022-08-22 11:12:52 | 来源: | 分类:SQLServer

      示例1
CREATE FUNCTION  [dbo].[函数名] 
(
   @Id int,@date1 datetime --入参
)
RETURNS varchar(1000) -- 返回值
AS
BEGIN
   
   declare @Str varchar(8000) 
   -- 业务逻辑  
   -- SQL思路拔高可以参考存储过程那篇文章,写的非常细
   -- http://www.canquick.com/article/ARTICLE_B176685DBB653F60CE765750.html
   RETURN  @Str   -- 返回值

END


go

grant execute, view definition on 函数名to []
go
      示例2
CREATE FUNCTION [dbo].[MaxNumber](
    @no1 float, @no2 float, @no3 float, @no4 float, @no5 float
)
    RETURNS float
AS
BEGIN
    declare @maxno float

    if isnull(@no1, 0) > isnull(@no2, 0)
        set @maxno = isnull(@no1, 0)
    else
        set @maxno = isnull(@no2, 0)

    if isnull(@maxno, 0) < isnull(@no3, 0)
        set @maxno = isnull(@no3, 0)


    if isnull(@maxno, 0) < isnull(@no4, 0)
        set @maxno = isnull(@no4, 0)


    if isnull(@maxno, 0) < isnull(@no5, 0)
        set @maxno = isnull(@no5, 0)


    return @maxno

END
go

阅读全文 »

页面相关 养老金测算

发表日期:2022-08-22 09:21:25 | 来源: | 分类:页面相关

      示例1
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>养老金测算</title>
    <meta name="keywords" content="养老金测算|退休工资预估" />
    <meta name="description" content="养老金测算|退休工资预估" />
</head>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>

<body>


<div style="background-color: #eacccc">
</div>
<div style="background-color: #a8d27e">
    <h4>计算公式为:</h4>
    <hr>
    <p>个人账户养老金=个人账户余额/139 粗算=(月工资*缴费比例*12月*缴费年限)/139</p>
    <p>基础养老金=(上年度全市平均工资+个人缴费工资)/2*缴费年限*1%</p>
    <p>月退休工资估算=个人账户养老金 +基础养老金 </p>
</div>
<hr>
<b>请输入:</b>
<br>月缴费基数:<input type="text" name="gz" value="10000">
<br> 缴费年限:<input type="text" name="nx" value="15">
<br> 缴费比例:<input type="text" name="bl" value="8">%
<br> 上年度全市平均工资:<input type="text" name="pj" value="7073">% <br>
<hr>

<div style="background-color: #b0a5e3">
    <h4>计算结果为:</h4>
    <hr>
    <p>个人账户养老金=(<span class="gz"></span>*<span class="bl"></span>%*12*<span class="nx"></span>)/139 = <span class="gr"></span></p>
    <p>基础养老金=(<span class="pj"></span>+<span class="gz"></span>)/2*<span class="nx"></span>*1%=<span class="jc"></span></p>
    <p>月退休工资估算=<span class="gr"></span> +<span class="jc"></span> = <span class="gs"></span></p>
    </p>
</div>


<h3>本测算只是预估个大概并不是准确的,且缴费基数、市平均工资、政策每年都会有浮动调整,谁也不可能几十年同一个基数缴费,仅供参考娱乐。</h3>

<script>

    function ab() {
        var gz = $("input[name=gz]").val() * 1;
        var nx = $("input[name=nx]").val() * 1;
        var bl = $("input[name=bl]").val() * 1;
        var pj = $("input[name=pj]").val() * 1;
        var gr = (gz * bl/100 *12 * nx / 139).toFixed(2) * 1;
        var jc = ((pj + gz) / 2 * nx * 0.01).toFixed(2) * 1;
        var gs = (gr + jc) .toFixed(2)

        $(".pj").text(pj);
        $(".gz").text(gz);
        $(".nx").text(nx);
        $(".bl").text(bl);
        $(".gr").text(gr);
        $(".jc").text(jc);
        $(".gs").text(gs);
    }

    ab();

    $("input").keyup(ab)


</script>
</body>
</html>

阅读全文 »

页面相关 canvas笔记

发表日期:2022-08-22 09:18:53 | 来源: | 分类:页面相关

      示例1
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style>
        #imooc{
            border:1px solid #ccc;
            /*width: 800px;*/
        }
    </style>
</head>
<body>

<canvas id="imooc" width="800" height="800"></canvas>

<script>
    // 根据id属性获取到canvas标签
    const canvas = document.getElementById('imooc');

    // 获取到canvas的 渲染上下文, 渲染上下文的概念后面有讲到
    const ctx = canvas.getContext('2d');


    ctx.fillStyle = 'orange';
    ctx.fillRect(10, 10, 100, 100);
    ctx.stroke();


    // 打线笔移动到起点
    ctx.moveTo(5,5);
    // 开始描线到终点
    ctx.lineTo(80,30);
    // 选择绿色的画笔
    ctx.strokeStyle="red";
    // 开始用画笔描边
    ctx.stroke();

    ctx.beginPath();
    //绘制第一条线段
    ctx.moveTo(10,10);
    ctx.lineTo(100,50);
    ctx.lineTo(200,10);
    ctx.strokeStyle="red";
    ctx.lineWidth=4;       //设置线段宽度为4px
    ctx.stroke();

    ctx.beginPath();
    //绘制第二条线段
    ctx.moveTo(10,30);
    ctx.lineTo(100,70);
    ctx.lineTo(200,30);
    ctx.strokeStyle="green"
    ctx.lineWidth=5;       //设置线段宽度为5px
    ctx.stroke();

    ctx.beginPath();
    //绘制第三条线段
    ctx.moveTo(10,50);
    ctx.lineTo(100,100);
    ctx.lineTo(200,50);
    ctx.strokeStyle="blue"
    ctx.lineWidth=6;       //设置线段宽度为6px
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(250,10);
    ctx.lineTo(250,100);
    ctx.lineTo(300,100);
    ctx.lineTo(300,10);
    ctx.lineTo(250,10);
    ctx.closePath();
    ctx.strokeStyle="blue"
    ctx.lineWidth=8
    ctx.stroke();

    ctx.rect(350,10,300,100);
    ctx.strokeStyle = "hlsa(60,50%,50%,0.5)"
    ctx.fillStyle = "hlsa(60,50%,50%,0.5)"
    ctx.fill();
    ctx.stroke();
    ctx.closePath();

    ctx.beginPath();
    ctx.rect(10,200, 100,100)
    let lg = ctx.createLinearGradient(10,100, 110,100) // 1. 创建渐变线
    lg.addColorStop(0, "#ff0000")    // 2. 设定关键点
    lg.addColorStop(0.5, "#fff")  // 2. 设定关键点
    lg.addColorStop(1, "#000")    // 2. 设定关键点
    ctx.fillStyle = lg;           // 3. 填充应用渐变线
    ctx.fill();


    ctx.beginPath();
    ctx.rect(200,200, 100,100)
    let lg1 = ctx.createLinearGradient(200,300, 300,300) // 1. 创建渐变线
    lg1.addColorStop(0, "#ff0000")    // 2. 设定关键点
    lg1.addColorStop(0.5, "#fff")  // 2. 设定关键点
    lg1.addColorStop(1, "#000")    // 2. 设定关键点
    ctx.strokeStyle = lg1;           // 3. 填充线性渐变
    ctx.stroke();


    ctx.beginPath();
    ctx.rect(350,200, 100,100)
    let lg2 = ctx.createRadialGradient(400,250,0,400,250,50) // 1. 创建径向渐变线
    lg2.addColorStop(0, "#ff0000")    // 2. 设定关键点
    lg2.addColorStop(0.5, "#fff")  // 2. 设定关键点
    lg2.addColorStop(1, "rgba(0,0,0,1)")    // 2. 设定关键点
    ctx.fillStyle = lg2;           // 3. 填充应用渐变线
    ctx.fill();

</script>
</body>
</html>

阅读全文 »

SQLServer 大坑之分页

发表日期:2022-08-20 10:46:18 | 来源: | 分类:SQLServer

      示例1
SELECT T1.*
FROM (SELECT result.*, ROW_NUMBER() OVER ( ORDER BY rand()) AS ROW_NUMBER
      FROM (SELECT * FROM [Users] WHERE ustate = 1) AS result
     ) AS T1
WHERE (T1.ROW_NUMBER BETWEEN 1 AND 10)
      示例2
SELECT top 10 *
FROM [Users]
WHERE ustate = 1
  and uid not in(
  SELECT  top ( N * 10) UID FROM [Users] WHERE ustate = 1 --N:0第一页 1第二页 类推
  )
      示例3
select top 10 *
from Users
where uid >
      (
          select isnull(max(uid),0) from (
                  select top N uid from Users order by uid  --N:0第一页 1第二页 类推
          ) A
      )
order by uid

阅读全文 »

SQLServer Link DB Server

发表日期:2022-08-20 09:56:53 | 来源: | 分类:SQLServer

      示例1
--查看当前链接情况:
select * from sys.servers;

--使用 sp_helpserver 来显示可用的服务器
Exec sp_helpserver

--显示使用sp_addlinkedserver来增加服务器链接
EXEC sp_addlinkedserver
    @server='LINKABC',--被访问的服务器别名
    @srvproduct='',
    @provider='SQLOLEDB',
    @datasrc='192.168.0.10\sql2008' --要访问的服务器IP[\实例名有就写没有]

--然后使用sp_addlinkedsrvlogin 来增加用户登录链接
EXEC sp_addlinkedsrvlogin
    'LINKABC', --被访问的服务器别名
    'false',
    NULL,
    'root', --帐号
    '123456' --密码

访问:
select * from [LINKABC].[abcDB].dbo.Users where uid = 1;
也支持IP形式:
select * from [192.168.0.10].[abcDB].dbo.Users where uid = 1;

-- 删除数据库链接
--与创建相反,要先删除登录账户
exec sp_droplinkedsrvlogin 'LINKABC',null

--然后再删除数据库链接
exec sp_dropserver 'LINKABC'

阅读全文 »

SQLServer 存储过程详解

发表日期:2022-08-19 15:57:32 | 来源: | 分类:SQLServer

      示例1
-- 如果没有参数 可以不写参数
CREATE PROCEDURE [存储名] @参数1 int, @参数2 varchar(50), @参数3 varchar(2000),@参数4 varchar(100)
as

-- 存储的主体

go
      示例2
exec [存储过程名字] @参数1=1,@参数2='aaa', @参数3sql='bbbb',@参数4where ='ccccc';
或者简写,即按字段顺序
exec [存储过程名字] 1,'aaa', 'bbbb','ccccc';

exec 也可以写成全称 execute
      示例3
-- 参数可以传入SQL语句直接在存储过程里执行,通常不建议这样干!
exec (@参数);

-- 传入的参数也可以是半截sql,然后再拼起来执行,通常不建议这样干!
-- 而且通常这么干都是在代码里把接收到的参数拼起来传,十有八九有SQL注入漏洞
exec ('delete from TestTab2 where a=b and d=c and '+@参数4where);
      示例4
-- 定义临时表
DECLARE @table_tmp table
(
   a int,
   b VARCHAR(50),
   c int,
   d int,
   e VARCHAR(50),
   f VARCHAR(50),
   g DECIMAL DEFAULT 0
);

-- 写法用法和普通表没什么区别,考验你的SQL基础能力罢了
insert into @table_tmp (a, b, c, d) select uid,username,age,10 from Users where type=3;

update @table_tmp set e=(select role_name from user_profile where uid = a)  where age > 18;

UPDATE t set t.f = r.role_name FROM @table_resoult as t, user_role as r where r.uid = t.a;

update @table_tmp set g=(select sum(money) from user_account where uid = a) where g = 0;

update c set c.d=b.score from @table_tmp c join ( select * from xxxxx ) b on c.a = b.uid and c.e = b.role;

--最后达到你想要的结果集了,你可以把虚拟表的数据插入到目标真实表
insert into targetTab(a1,b1,c1,d1,e1,f1,g1) select a,b,c,d,e,f,g from @table_tmp;
-- 或者存储过程直接返回临时表的结果
select *  from @table_tmp;
      示例5
--可以定义变量
declare @var1 varchar(50)

--给定义的变量赋值
select @username = username from users where UID = 1;

--使用变量
update user_house set update_time=getdate(), username=@username where uid = 1;
      示例6
--开启事务
begin tran

-- 这里进行业务操作
-- ……

--如果有错
if (0 <> @@ERROR)
    begin 
    
        --事务回滚
        rollback tran;
        
        
        -- 返回错误码
        select -1;
    end
else
    begin 
    
        --提交事务
        commit tran;
        
        -- 可以返回修改行数或 其它内容
        select @@ROWCOUNT;
    end
      示例7
--定义变量
declare @uid int,@username varchar(50);

-- 定义游标 填充数据
declare c1 cursor for select UID,UName  from Users where uuid <> 0;

--开启游标
open c1 aa:fetch next from c1 into @uid,@username

-- 循环
while @@fetch_Status = 0
    begin
        -- 业务逻辑
    end
    
    
-- 关闭游标
close c1

-- 销毁游标
deallocate c1

阅读全文 »

SQLServer 大坑之事务回滚占自增ID

发表日期:2022-08-18 11:33:59 | 来源: | 分类:SQLServer

主键如果是自增的,当你使用事务时,即便是事务回滚了,你的下一个ID会被占用,再次插入会跳一个数。

这个大坑在一些业务场景下极其讨厌,比如这张表的ID是某编号你希望是连续的那就很膈应了。

image.png

你可以看到上面的例子,执行多次后ID全是间隔的,就是因为回滚事务的那条也占用了ID自增。

注意:mysql也是如此

阅读全文 »

SQLServer 存储报错:SQLSTATE[IMSSP]: The active result for the query contains no fields.

发表日期:2022-08-16 17:00:00 | 来源: | 分类:SQLServer

存储报错:SQLSTATE[IMSSP]: The active result for the query contains no fields.

原因:

一般执行execute语句,也就是增删改语句会返回修改记录数的行数。执行select 是返回记录。

存储里可能是先执行了增删改,最后是select 返回结果,就会报这个错。

在存储里增加这句话,让存储不返回影响的记录数就可以了。

SET NOCOUNT ON

阅读全文 »

SQLServer 大坑之导入数据

发表日期:2022-08-16 16:49:34 | 来源: | 分类:SQLServer

Cannot insert explicit value for identity column in table 'test' when IDENTITY_INSERT is set to OFF

这句报错的大致意思就是这张表有自增列,不能直接导入。

SQLServer 导入表,如果这张表的ID是自增那就非常烦,导入会报错。提示你必须先允许插入自增,插入完成再关闭。

set IDENTITY_INSERT 表名 on

insert into ……

insert into ……

set IDENTITY_INSERT 表名 off

当然要是一张表还好办,我要导入N张表,可是把我烦死了,而且单表SQL文件特别大,打开都费劲。

阅读全文 »

SQLServer 大坑之浮点数显示问题

发表日期:2022-08-15 16:47:01 | 来源: | 分类:SQLServer

以下情况在php+SQLserver下经过验证是存在问题的,其它语言请自酌。

一、字段类型是float类型时

image.png

image.png  

输出

image.png 

 显示正常,十分具有迷惑性,开发的时候你以为是没问题的,

但是

image.png

输出

image.png 

150.12 显示为 15.119999999999999

这是太坑了,我们的项目是重构一个用了15年+的项目,库不变只做程序,项目里见到最多的字段就是金额小数点,做到后面发现这个问题,所有输出的位置到处都得格式化去改!

还有一个问题是,如果你希望的是x.xx这种保留两位的格式,不好意思,不建议用float类型!因为12.00 进库即存为12,出库也12,不格式化没法是12.00!

对比之下mysql是没有问题的,因为是是这样定义的float(9,2)保留两位!


二、字段类型是 decimal(18, 2) 类型时

0.00 显示为 .00

image.png

输出:

image.png

导致于 所有显示地方都得把 .00 换成 0.00。

(后发现可能是php-SQLserver驱动的兼容问题一个项目用的pdo_dblib显示是好的,一个用的pdo_sqlsrv显示不正常,可能跟驱动版本有关系,反正用php+SQLserver的小伙伴格外注意一下),

阅读全文 »

SQLServer 大坑之数字乘除计算

发表日期:2022-08-15 12:16:52 | 来源: | 分类:SQLServer

10 / 4 * 4 = ?  , 小学毕业都知道应该还是10,

我们用mysql试一下:

image.png

依然是10,其实当计算出小数,mysql会自动转型为float,但是注意,SQLserver不会!

image.png

得出的结果是8! 为什么是8呢,有点离谱。

因为SQLserver是强类型的,10/4 = 2 ,2*4=8,因此如果你的字段是int类型的你想在SQL里做乘除那你可得想好了,记得先把计算的字段转型为float

image.png

阅读全文 »

SQLServer 大坑之null 判断

发表日期:2022-08-15 12:00:34 | 来源: | 分类:SQLServer

例如

image.png

三条数据,我们找出 misMoney是null的

image.png

然而一条也没出来!

mysql 的null 你写 where a = null / where a <> null 都没毛病,当然我一直也认为其实能这样判断是最好最方便,但是SQLserver不支持!

尤其现在绝大多数程序员及项目都用的是mysql,所以很多程序员没用过甚至不了解SQLserver。我面试过很多程序员,答对的很少,全然不知SQL语句 null 的正确判断写法。

正确写法

 image.png

一定要有 is null  或 is not null !

参考另一篇文章:

SQLServer大坑之<>判断

阅读全文 »

SQLServer 大坑之不等于判断

发表日期:2022-08-15 11:50:20 | 来源: | 分类:SQLServer

例如有三条数据:

image.png

我们想找出 posMoney和misMoney不一致的数据,逻辑很简单 我们通常想到且写的是:

where posMoney <> misMoney ,理论上出的结果是王五和李四。

然后我们看结果

image.png

只有一条王五!!  20000和null 的竟然出不来!

这就是SQLserver的大坑,一定要注意,mysql是没有问题的,但是SQLserver是不能和可能存在null列进行对比,

当然我事先是知道这个的,但是!!有时候我们认为的数据实际不应该有null,但现实是前几天发现业务系统里这列数据居然因为某些异常情况存在很多null值,以至于我这样写成为了被错误。这是最坑的,这才是更是应该注意的,所以代码最好把所有可能性想到,避免让别人的错误成为自己的错。

所以,在SQLserver里如果是金额等严谨性判断<> 最好这样写:

image.png

不管你认为可不可能有null 总之先把null替换为数字0或空字符串'',然后再对比 <>,多么痛的领悟……

阅读全文 »

全部博文(1580)
集速网 copyRight © 2015-2022 宁ICP备15000399号-1 宁公网安备 64010402001209号
与其临渊羡鱼,不如退而结网
欢迎转载、分享、引用、推荐、收藏。