How to order the numbers? - sql

Table1
id value
---------
1 100
2A 200
2 300
10 500
8 200
....
Select *
from table1
order by id
Showing output as
id value
------------
1 100
10 500
2A 200
2 300
8 200
....
How to make a proper order?
Expected output
id value
----------
1 100
2 300
2A 200
8 200
10 500
....

If it is fixed that last character may be character then you can try following query
WITH A(ID)
AS
(
SELECT '1'
UNION ALL
SELECT '2C'
UNION ALL
SELECT '2A'
UNION ALL
SELECT '2'
UNION ALL
SELECT '10'
)
SELECT *
FROM A
ORDER BY
convert(int,
Case When IsNumeric(ID) = 0 then left(ID,len(id)-1)
Else ID END
) , Case When IsNumeric(ID) = 0 then RIGHT(ID,1) Else '0' END
and if it is variable then you can write a function that replace charecter with its ansi value or 0 . and then put order by close on that column .

CREATE FUNCTION [dbo].[RemoveNonAlphaCharacters](#Temp varchar(1000))
RETURNS int
AS
BEGIN
WHILE PatIndex ('%[^0-9]%', #Temp) > 0
SET #Temp = Stuff( #Temp, PatIndex('%[^0-9]%' , #Temp ), 1, '')
RETURN #Temp
END
SELECT id, value
FROM dbo.Table1
ORDER BY [dbo].[RemoveNonAlphaCharacters](id) ASC

SELECT
LEFT(ID,1),
RIGHT(ID,1),
*
FROM table1
ORDER BY LEFT(ID,1),RIGHT(ID,1)
should do the trick, I'm not even sure if the left and right is needed in the selected statement.

Select *
from table1
order by cast(replace(lower(id), 'abcdefg', '') as int),
replace(id, '0123456789','');

SELECT * FROM table1 ORDER BY CAST(id as varchar(50))

Related

How to arrange continuous serial number in to two or multiple column sequentially in sql server?

I want to print or display 1 to 10 or any max number in two column format using MS Sql-Server query.
Just like below attached screen shot image.
So please give any suggestion.
Using a couple of inline tallies would be way faster than a WHILE. This version will go up to 1000 integers (500 rows):
DECLARE #Start int = 1,
#End int = 99;
SELECT TOP(CONVERT(int,CEILING(((#End*1.) - #Start + 1)/2)))
(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1)*2 + #Start AS Number1,
CASE WHEN (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1)*2 + #Start +1 <= #End THEN (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1)*2 + #Start +1 END AS Number2
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N1(N)
CROSS APPLY (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N2(N)
CROSS APPLY (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N3(N);
An alternative way that looks less messy with the CASE and TOP would be to use a couple of CTEs:
WITH Tally AS(
SELECT TOP(#End - #Start + 1)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 + #Start AS I
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N1(N)
CROSS APPLY (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N2(N)
CROSS APPLY (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N3(N)),
Numbers AS(
SELECT I AS Number1,
LEAD(I) OVER (ORDER BY I) AS Number2
FROM Tally)
SELECT Number1,
Number2
FROM Numbers
WHERE Number1 % 2 = #Start % 2;
I like to use recursive queries for this:
with cte (num1, num2) as (
select 1, 2
union all
select num1 + 2, num2 + 2 from cte where num2 < 10
)
select * from cte order by num1
You control the maximum number with the inequality condition in the recursive member of the cte.
If you need to generate more than 100 rows, you need to add option(maxrecursion 0) at the very end of the query.
Assuming you are starting with a table with one column, you can use:
select min(number), max(number)
from sample_data
group by floor( (number - 1) / 2);
Alternatively, set-based solution using window functions:
use tempdb
;with sample_data as (
select 1 as val union all
select 2 union all
select 3 union all
select 4 union all
select 5 union all
select 6 union all
select 7 union all
select 8 union all
select 9 union all
select 10
)
, sample_data_split as
(
select
val
, 2- row_number() over (order by val) % 2 as columnid
, NTILE((select count(*) / 2 from sample_data) ) over (order by val) groupid
from sample_data
)
the intermediate result of sample_data_split is:
val columnid groupid
1 1 1
2 2 1
3 1 2
4 2 2
5 1 3
6 2 3
7 1 4
8 2 4
9 1 5
10 2 5
and then to get the resultset into a desired format:
select
min(case when columnid = 1 then val end) as column1
, min(case when columnid = 2 then val end) as column2
from sample_data_split
group by groupid
column1 column2
1 2
3 4
5 6
7 8
9 10
Those CTEs can be merged into a single SELECT:
select
min(case when columnid = 1 then val end) as column1
, min(case when columnid = 2 then val end) as column2
from
(
select
val
, 2- row_number() over (order by val) % 2 as columnid
, NTILE((select count(*) / 2 from sample_data) ) over (order by val) groupid
from sample_data
) d
group by groupid
The positive side of a such approach, that it scales well and has no upper boundary on how much rows to be processed
So I got this solution on it as below...
declare #t table
(
id int identity(1,1),
Number_1 int,
Number_2 int
)
declare #min int=1
declare #max int=10
declare #a int=0;
declare #id int=0
while(#min<=#max)
begin
if(#a=0)
begin
insert into #t
select #min,null
set #a=1
end
else if(#a=1)
begin
select top 1 #id=id from #t order by id desc
update #t set Number_2=#min where id=#id
set #a=0
end
set #min=#min+1
end
select Number_1,Number_2 from #t

SQL Rank() function excluding rows

Consider I have the following table.
ID value
1 100
2 200
3 200
5 250
6 1
I have the following query which gives the result as follows. I want to exclude the value 200 from rank function, but still that row has to be returned.
SELECT
CASE WHEN Value = 200 THEN 0
ELSE DENSE_RANK() OVER ( ORDER BY VALUE DESC)
END AS RANK,
ID,
VALUE
FROM #table
RANK ID VALUE
1 5 250
0 2 200
0 3 200
4 1 100
5 6 1
But I want the result as follows. How to achieve it?
RANK ID VALUE
1 5 250
0 2 200
0 3 200
2 1 100
3 6 1
If VAL column is not nullable, taking into account NULL is the last value in ORDER BY .. DESC
select *, dense_rank() over (order by nullif(val,200) desc) * case val when 200 then 0 else 1 end
from myTable
order by val desc;
There is no way to exclude Val in Dense Rank currently ,unless you filter in where clause..that is the reason ,you get below result
RANK ID VALUE
1 5 250
0 2 200
0 3 200
4 1 100
5 6 1
You will need to filter once and then do a union all
;with cte(id,val)
as
(
select 1, 100 union all
select 2, 200 union all
select 3, 200 union all
select 5, 250 union all
select 6, 1 )
select *, dense_rank() over (order by val desc)
from cte
where val<>200
union all
select 0,id,val from cte where val=200
You could split the ranking in to separate queries for the values you want to include/exclude from the ranking and UNION ALL the results like so:
Standalone executable example:
CREATE TABLE #temp ( [ID] INT, [value] INT );
INSERT INTO #temp
( [ID], [value] )
VALUES ( 1, 100 ),
( 2, 200 ),
( 3, 200 ),
( 5, 250 ),
( 6, 1 );
SELECT *
FROM ( SELECT 0 RANK ,
ID ,
value
FROM #temp
WHERE value = 200 -- set rank to 0 for value = 200
UNION ALL
SELECT DENSE_RANK() OVER ( ORDER BY value DESC ) AS RANK ,
ID ,
value
FROM #temp
WHERE value != 200 -- perform ranking on records != 200
) t
ORDER BY value DESC ,
t.ID
DROP TABLE #temp
Produces:
RANK ID value
1 5 250
0 2 200
0 3 200
2 1 100
3 6 1
You can modify the ordering at the end of the statement if required, I set it to produce your desired results.
You can also try this, too:
SELECT ISNULL(R, 0) AS Rank ,t.id ,t.value
FROM tbl1 AS t
LEFT JOIN ( SELECT id ,DENSE_RANK() OVER ( ORDER BY value DESC ) AS R
FROM dbo.tbl1 WHERE value <> 200
) AS K
ON t.id = K.id
ORDER BY t.value DESC
The solution in the original question was actually pretty close. Just adding a partition clause to the dense_rank can do the trick.
SELECT CASE
WHEN VALUE = 200 THEN 0
ELSE DENSE_RANK() OVER(
PARTITION BY CASE WHEN VALUE = 200 THEN 0 ELSE 1 END
ORDER BY VALUE DESC
)
END AS RANK
,ID
,VALUE
FROM #table
ORDER BY VALUE DESC;
The 'partition by' creates separate groups for the dense_rank such that the order is performed on these groups individually. This essentially means you create two ranks at the same time, one for the group without the 200 value and one for the group with only the 200 value. The latter one to be set to 0 in the 'case when'.
Standalone executable example:
DECLARE #table TABLE
(
ID INT NOT NULL PRIMARY KEY
,VALUE INT NULL
)
INSERT INTO #table
(
ID
,VALUE
)
SELECT 1, 100
UNION SELECT 2, 200
UNION SELECT 3, 200
UNION SELECT 5, 250
UNION SELECT 6, 1;
SELECT CASE
WHEN VALUE = 200 THEN 0
ELSE DENSE_RANK() OVER(
PARTITION BY CASE WHEN VALUE = 200 THEN 0 ELSE 1 END
ORDER BY VALUE DESC
)
END AS RANK
,ID
,VALUE
FROM #table
ORDER BY VALUE DESC;
RANK ID VALUE
1 5 250
0 2 200
0 3 200
2 1 100
3 6 1

How to use aggregate function in update in SQL server 2012

I Tried as shown below:
CREATE TABLE #TEMP
(
ID INT,
EmpID INT,
AMOUNT INT
)
INSERT INTO #TEMP VALUES(1,1,10)
INSERT INTO #TEMP VALUES(2,1,5)
INSERT INTO #TEMP VALUES(3,2,6)
INSERT INTO #TEMP VALUES(4,3,8)
INSERT INTO #TEMP VALUES(5,3,10)
.
.
.
SELECT * FROM #TEMP
ID EmpID AMOUNT
1 1 10
2 1 5
3 2 6
4 3 8
5 4 10
UPDATE #TEMP
SET AMOUNT = SUM(AMOUNT) - 11
Where EmpID = 1
Expected Output:
Table consists of employeeID's along with amount assigned to Employee I need to subtract amount from amount filed depending on employee usage. Amount "10" should be deducted from ID = 1 and amount "1" should be deducted from ID = 2.
Amount: Credits available for that particular employee depending on date.
So i need to reduce credits from table depending on condition first i need to subtract from old credits. In my condition i need to collect 11 rupees from empID = 1 so first i need to collect 10 rupee from ID=1 and 1 rupee from the next credit i.e ID=2. For this reason in my expected output for ID=1 the value is 0 and final output should be like
ID EmpID AMOUNT
1 1 0
2 1 4
3 2 6
4 3 8
5 4 10
Need help to update records. Check error in my update statement.
Declare #Deduct int = -11,
#CurrentDeduct int = 0 /*this represent the deduct per row */
update #TEMP
set #CurrentDeduct = case when abs(#Deduct) >= AMOUNT then Amount else abs(#Deduct) end
, #Deduct = #Deduct + #CurrentDeduct
,AMOUNT = AMOUNT - #CurrentDeduct
where EmpID= 1
I think you want the following: subtract amounts from 11 while remainder is positive. If this is true, here is a solution with recursive cte:
DECLARE #t TABLE ( id INT, amount INT )
INSERT INTO #t VALUES
( 1, 10 ),
( 2, 5 ),
( 3, 3 ),
( 4, 2 );
WITH cte
AS ( SELECT * , 17 - amount AS remainder
FROM #t
WHERE id = 1
UNION ALL
SELECT t.* , c.remainder - t.amount AS remainder
FROM #t t
CROSS JOIN cte c
WHERE t.id = c.id + 1 AND c.remainder > 0
)
UPDATE t
SET amount = CASE WHEN c.remainder > 0 THEN 0
ELSE -remainder
END
FROM #t t
JOIN cte c ON c.id = t.id
SELECT * FROM #t
Output:
id amount
1 0
2 0
3 1
4 2
Here I use 17 as start remainder.
If you use sql server 2012+ then you can do it like:
WITH cte
AS ( SELECT * ,
17 - SUM(amount) OVER ( ORDER BY id ) AS remainder
FROM #t
)
SELECT id ,
CASE WHEN remainder >= 0 THEN 0
WHEN remainder < 0
AND LAG(remainder) OVER ( ORDER BY id ) >= 0
THEN -remainder
ELSE amount
END
FROM cte
First you should get a cumulative sum on amount:
select
id,
amount,
sum(amount) over (order by id) running_sum
from #TEMP;
From here we should put 0 on rows before running_sum exceeds the value 11. Update the row where the running sum exceeds 11 and do nothing to rows after precedent row.
select
id,
amount
running_sum,
min(case when running_sum > 11 then id end) over () as decide
from (
select
id,
amount,
sum(amount) over (order by id) running_sum
from #TEMP
);
From here we can do the update:
merge into #TEMP t
using (
select
id,
amount
running_sum,
min(case when running_sum > 11 then id end) over () as decide
from (
select
id,
amount,
sum(amount) over (order by id) running_sum
from #TEMP
)
)a on a.id=t.id
when matched then update set
t.amount = case when a.id = a.decide then a.running_sum - 11
when a.id < a.decide then 0
else a.amount
end;
See an SQLDFIDDLE

How to display a time in specific format

Using SQL Server 2005
Table1
ID TimeColumn
001 13.00
002 03.30
003 14.00
004 23.00
005 08.30
...
Table1 Format
TimeColumn Format: HH:MM
TimeColumn Datatype is nvarchar
TimeColumn will display the time One Hour or HalfHour
TimeColumn will not display 08.20, 08.56. It will display the time like 08.00, 08.30.
I want to display a time like 13 instead of 13.00, 3.5 instead of 03.30.
Expected Output
ID TimeColumn Value
001 13.00 13
002 03.30 3.5
003 14.00 14
004 23.00 23
005 18.30 18.5
...
How to make a query for the above condition?
Based on your facts, there are only 2 cases for the last 3 digits, either
.30; or
.00
So we just replace them
SELECT
ID,
TimeColumn,
Value = replace(replace(TimeColumn, '.30', '.5'), '.00', '')
From Table1
EDIT
To drop the leading 0, you can use this instead (the Value column is numeric)
SELECT
ID,
TimeColumn,
Value = round(convert(float,TimeColumn)*2,0)/2
From Table1
Or if you need it to be varchar
SELECT
ID,
TimeColumn,
Value = right(round(convert(float,TimeColumn)*2,0)/2,5)
From Table1
Try this
SELECT
DATEPART(hour,TimeColumn) +
1 / DATEPART(minute,TimeColumn) * 60
AS Value
FROM Table1
This is where TimeColumn is DateTime. For Column Type NVarChar use a String function to split hours and minutes.
I believe that is how SQL Server stores datetime, you then format it with your flavor of programming language.
Here is how you can do it:
select SUBSTRING('20.30', 1, 2) + (case when SUBSTRING('20.30', 4, 2) = '30' then '.5' else '' end)
just replace '20.30' with your column name and add from clause
Declare #table table (ID nvarchar(10),timevalue nvarchar(10))
INSERT INTO #table values('001','13.00')
INSERT INTO #table values('002','03.30')
INSERT INTO #table values('003','14.00')
INSERT INTO #table values('004','23.00')
INSERT INTO #table values('005','08.30')
select (CASE WHEN (CHARINDEX('.3',timevalue)>0) then convert(varchar(2),timevalue,2)
else convert(varchar(2),timevalue,2) + '.5'
end)
from #table
With TestInputs As
(
Select '001' As Id, Cast('13.00' As nvarchar(10)) As TimeColumn
Union All Select '002','03.30'
Union All Select '003','14.00'
Union All Select '004','23.00'
Union All Select '005','08.30'
Union All Select '006','08.26'
Union All Select '007','08.46'
Union All Select '008','08.56'
)
, HoursMinutes As
(
Select Id, TimeColumn
, Cast( Substring(TimeColumn
, 1
, CharIndex('.', TimeColumn) - 1 ) As int ) As [Hours]
, Cast( Substring(TimeColumn
, CharIndex('.', TimeColumn) + 1
, Len(TimeColumn) ) As int ) As [Minutes]
From TestInputs
)
Select Id, TimeColumn
, [Hours] + Case
When [Minutes] < 30 Then 0.0
When [Minutes] < 60 Then 0.5
Else 1
End As Value
From HoursMinutes

row with minimum value of a column

Having this selection:
id IDSLOT N_UM
------------------------
1 1 6
2 6 2
3 2 1
4 4 1
5 5 1
6 8 1
7 3 1
8 7 1
9 9 1
10 10 0
I would like to get the row (only one) which has the minimun value of N_UM, in this case the row with id=10 (10 0).
select * from TABLE_NAME order by COLUMN_NAME limit 1
I'd try this:
SELECT TOP 1 *
FROM TABLE1
ORDER BY N_UM
(using SQL Server)
Try this -
select top 1 * from table where N_UM = (select min(N_UM) from table);
Use this sql query:
select id,IDSLOT,N_UM from table where N_UM = (select min(N_UM) from table));
Method 1:
SELECT top 1 *
FROM table
WHERE N_UM = (SELECT min(N_UM) FROM table);
Method 2:
SELECT *
FROM table
ORDER BY N_UM
LIMIT 1
A more general solution to this class of problem is as follows.
Method 3:
SELECT *
FROM table
WHERE N_UM IN (SELECT MIN(N_UM) FROM table);
Here is one approach
Create table #t (
id int,
IDSLOT int,
N_UM int
)
insert into #t ( id, idslot, n_um )
VALUES (1, 1, 6),
(2,6,2),
(3,2,1),
(4,4,1),
(5,5,1),
(6,8,1),
(7,3,1),
(8,7,1),
(9,9,1),
(10, 10, 0)
select Top 1 *
from #t
Where N_UM = ( select MIN(n_um) from #t )
select TOP 1 Col , COUNT(Col) as minCol from employee GROUP by Col
order by mindep asc