如何解决 不能以 DISTINCT 方式选择 text、ntext 或 image 数据类型

distinct去重,如果遇到text字段,可以用以下方法解决

 

1.用not exists

select * from tab a
where not exists (
  select 1 from tab b
  where b.col1 = a.col1
  and b.col2 = a.col2
  ...
  )

 

2.转成字符型
CONVERT(VARCHAR(8000),你的字段)

select distinct * from (

select id, convert(varchar(8000), ntextCol) as colName from XXX

)

 

用EXISTS替换DISTINCT: 当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换, EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.

例子:

(低效):

SELECT  DISTINCT  DEPT_NO,DEPT_NAME  FROM  DEPT D , EMP E WHERE  D.DEPT_NO = E.DEPT_NO

(高效):

SELECT  DEPT_NO,DEPT_NAME  FROM  DEPT D  WHERE  EXISTS ( SELECT ‘X' FROM  EMP E  WHERE E.DEPT_NO = D.DEPT_NO);   

用EXISTS的确可以替代DISTINCT,不过以上方案仅适合DEPT_NO为唯一主键的情况。 如果要去掉重复记录,需参照以下方法:

SELECT  * FROM  EMP WHERE  DEPT_NO EXISTS(select Max(DEPT_NO) FROM  DEPT D , EMP E  WHERE E.DEPT_NO = D.DEPT_NO GROUP BY D.DEPT_NO)  

 

得到重复记录数

SELECT  * FROM  EMP WHERE  DEPT_NO NOT EXISTS(select Max(DEPT_NO) FROM  DEPT D , EMP E  WHERE E.DEPT_NO = D.DEPT_NO GROUP BY D.DEPT_NO)

 

 在我们进行sql注入的过程中常常会用到union查询方法,大多数情况下使用union查询法可以让我们很快的知道目标的数据组织方式。然而当我们遇到ntext、text或image数据类型时,union查询就不太管用了。以sql  server为例,在这种情况下会抛出如下错误:ntext 数据类型不能选为 DISTINCT,因为它不可比。

     这里,我以sql  server数据库为测试环境来进行分析。因为ntext、text、image数据字段可能存储非常多的数据,默认的情况下,数据库为提高效率会强制排除以上类型的字段中的相同的数据,这样就相当于在sql查询语句中加入了distinct关键字。而又因为这种类型的数据量可能非常大,数据库无法对这种类型的字段进行有效的比较,而distinct又要求数据库进行数据比较,从而导致带有unionr的sql语句执行错误,造成上述现象。

    了解了出错的原理我们就可以在执等的sql语句中加入相应的条件来使sql能正确执行。从上面可以看出,sql语句无法执行的原因是因为数据库去检查union的数据是否相同,那么我们只需要去掉这个默认的条件就可以了。解决的方法就是在union关键字后边加上“all”关键字。

    下面用实例来演示这种类型的union注入。首先创建两个表: CREATE TABLE [dbo].[ntextTest](  [id]  [int] NOT NULL,  [name] [nchar](10) NULL,  [target] [ntext] NULL ) ON  [PRIMARY] TEXTIMAGE_ON [PRIMARY] CREATE TABLE [dbo].[support](  [col1]  [nchar](10) NULL,  [col2] [nchar](10) NULL ) ON  [PRIMARY] 然后分别在这两个表中插入数据: insert into ntextTest  values(1,'aaa','adfsfs') insert into ntextTest  values(2,'test','aaaa') insert into support  values('aa','bb') 之后执行下列查询: select * from ntextTest union  select 1,2,col1  from support 一如即往,没有成功。再执行: select * from ntextTest union all select  1,col1,col2 from support 这次正常返回结果!接下来被卡住的sql注入可以继续进行了。

      上面所讲的问题的前提是ntext、text、image等数据类型出现在union查询的前面部分,在进行sql注入时,注入对象原有的查询语句中包含ntext数据类型即是这种情况。还有另一种情况是在我们注入时希望查询ntext数据字段的内容。这种情况还有以有另一种操作方式。比如要注入一个地址:http://www.test.com/show.asp?id=1,假定其后后的sql查询语句为:select id,productName,productInfo  from product where id=@id,其中productName和productInfo都为nvarchar类型,如果我们想要查询这个网站后台的article表中的文章的内容(用content表示,为ntext类型)可以用substring  函数来实现。用substring 可以将ntext数据截取一部分出来作为nvarchar类型返回,这样可以绕过ntext类型。如我们做如下构造:http://www.test.com/show.asp?id=1 and  1=2 union select 1,2,…,substring(content,1,200),...n from article where id=XX   下面附上substring详细用法:

substring函数: {     返回值:返回字符、binary、text 或 image  表达式的一部分。     语法:SUBSTRING ( e­xpression , start , length  )      参数:         e­xpression:是字符串、二进制字符串、text、image、列或包含列的表达式。不要使用包含聚合函数的表达式。         start:是一个整数,指定子串的开始位置。            length:是一个整数,指定子串的长度(要返回的字符数或字节数)。      返回类型:            1)、如果  e­xpression 是支持的字符数据类型,则返回字符数据。            2)、如果  e­xpression 是支持的  binary 数据类型,则返回二进制数据。              返回字符串的类型与给定表达式的类型相同(表中显示的除外)。

 

}

 

给定的表达式 返回类型
text varchar
image varbinary
ntext nvarchar

     注释:             在字符数中必须指定使用 ntextchar varchar 数据类型的偏移量(start length)。在字节数中必须指定使用 textimagebinary varbinary 数据类型的偏             移量。

 

   

ps:之后以写这篇文章是因为本人在注入过程中遇到了上面的问题,百度了好久都没有找到有用的信息。相信很多像我一样的小菜遇到这样的问题也难以解决,希望这篇文章对小菜有所帮助。另本人初学安全技术,很多东西一知半解,难免出错,如果老鸟们发现了还请指点!

 

 

用NOT EXISTS替代NOT IN 

  在子查询中,NOT IN子句将执行一个内部的排序和合并。 无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历)。 为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS.

  例如:

 

  SELECT …   FROM EMP   WHERE DEPT_NO NOT IN (SELECT DEPT_NO   FROM DEPT   WHERE DEPT_CAT=’A’);

  为了提高效率。改写为:

 (方法一: 高效)

 

  SELECT ….   FROM EMP A,DEPT B   WHERE A.DEPT_NO = B.DEPT(+)   AND B.DEPT_NO IS NULL   AND B.DEPT_CAT(+) = ‘A’

  (方法二: 最高效)

 

  SELECT ….   FROM EMP E   WHERE NOT EXISTS (SELECT ‘X’   FROM DEPT D   WHERE D.DEPT_NO = E.DEPT_NO   AND DEPT_CAT = ‘A’); 用EXISTS替换DISTINCT 

  当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换

  例如:

  低效:

 

  SELECT DISTINCT DEPT_NO,DEPT_NAME   FROM DEPT D,EMP E   WHERE D.DEPT_NO = E.DEPT_NO

 高效:

 

  SELECT DEPT_NO,DEPT_NAME   FROM DEPT D   WHERE EXISTS ( SELECT ‘X’   FROM EMP E   WHERE E.DEPT_NO = D.DEPT_NO);

  EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果。

识别‘低效执行’的SQL语句

  用下列SQL工具找出低效SQL:

 

  SELECT EXECUTIONS , DISK_READS, BUFFER_GETS,   ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio,   ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,   SQL_TEXT   FROM V$SQLAREA   WHERE EXECUTIONS>0   AND BUFFER_GETS > 0   AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8   ORDER BY 4 DESC;

  (虽然目前各种关于SQL优化的图形化工具层出不穷,但是写出自己的SQL工具来解决问题始终是一个最好的方法)

你可能感兴趣的:(如何解决 不能以 DISTINCT 方式选择 text、ntext 或 image 数据类型)