Select rows by applying whatever condition(if or case) - sql

I have a set of records suppose below:
Id Name status date
1 xx 1 2016-06-27 14:05:17.447
2 yy 2 2016-06-27 14:05:17.447
3 zz 1 2016-06-27 14:05:17.447
4 aa 2 2016-06-27 14:05:17.447
5 bb 2 2016-06-27 14:05:17.447
I want to select all the rows from above but
for the rows who have status=1, i want to apply a condition that
select if status=1 and date<=getdate
How can I do that?

select
Id,
Name,
case when status =1 and date<getdate() then 'I want to select this row' else I don't want to select this row end as statuss
,date
from
yourtable
Update: as per your edit,you need to apply your conditions in where clause
select * from yourtable
where status=1 and date<getdate()

The simplest way I can think of, unless status is nullable:
SELECT Id, Name, Status, Date
FROM TableName
WHERE status <> 1
OR date <= getdate()
If it is nullable, you can do this:
SELECT Id, Name, Status, Date
FROM TableName
WHERE ISNULL(status, 0) <> 1
OR date <= getdate()

Try this:
CREATE TABLE #Status
(
Id INT
, Name CHAR(2)
, status INT
, date DATETIME
);
INSERT INTO #Status
( Id, Name, status, date )
VALUES ( 1 -- Id - int
, 'xx' -- Name - char(2)
, 1 -- status - int
, '2016-06-27 14:05:17.447' -- date - datetime
),
( 2 -- Id - int
, 'yy' -- Name - char(2)
, 2 -- status - int
, '2016-06-27 14:05:17.447' -- date - datetime
),
( 3 -- Id - int
, 'zz' -- Name - char(2)
, 1 -- status - int
, '2016-06-27 14:05:17.447' -- date - datetime
),
( 4 -- Id - int
, 'aa' -- Name - char(2)
, 2 -- status - int
, '2016-06-27 14:05:17.447' -- date - datetime
),
( 5 -- Id - int
, 'bb' -- Name - char(2)
, 2 -- status - int
, '2016-06-27 14:05:17.447' -- date - datetime
),
( 6 -- Id - int
, 'cc' -- Name - char(2)
, 1 -- status - int
, '2016-07-27 14:05:17.447' -- date - datetime
);
SELECT *
FROM #Status;
WITH cte
AS ( SELECT *
FROM #Status
WHERE status <> 1
) ,
cteStatus1
AS ( SELECT *
FROM #Status
WHERE status = 1
AND date <= GETDATE()
)
SELECT *
FROM cte
UNION
SELECT *
FROM cteStatus1;

Related

Comma separated values from multi columns as rows

I have a table tbl_commaseperate with columns ID, MONNAME, IP and POLICY whose values are:
ID | MONNAME | IP | POLICY
-------------------------------
X | NOV | 1,2,3 | 4,5,6,7
where IP and POLICY have comma separated values.
My desired result looks like as below:
ID | MONNAME | IP | POLICY
------------------------------
X | NOV | 1 | 4
X | NOV | 2 | 5
X | NOV | 3 | 6
X | NOV | null | 7
The output is in no particular order. Also, in your desired output you don't seem to care which pair was first, which second etc. (but that can be preserved in the query, if needed).
I added a row for more testing; I have NULL for policy - which is how I realized I needed the coalesce() around the regexp_count.
with
inputs ( id ,monname, ip , policy ) as (
select 'X', 'NOV', '1,2,3' , '4,5,6,7' from dual union all
select 'X', 'DEC', '6,3,8', null from dual
)
-- end of test data; solution (SQL query) begins below this line
select id, monname,
regexp_substr(ip , '[^,]+', 1, level) as ip,
regexp_substr(policy, '[^,]+', 1, level) as policy
from inputs
connect by level <= 1 + greatest( coalesce(regexp_count(ip , ','), 0),
coalesce(regexp_count(policy, ','), 0) )
and prior id = id
and prior monname = monname
and prior sys_guid() is not null
;
ID MONNAME IP POLICY
-- ------- ----- -------
X DEC 6
X DEC 3
X DEC 8
X NOV 1 4
X NOV 2 5
X NOV 3 6
X NOV 7
7 rows selected
Please try this one.
Create a function to split comma separated string.
CREATE FUNCTION [dbo].[fnSplit](
#sInputList VARCHAR(max) -- List of delimited items
, #sDelimiter VARCHAR(max) = ',' -- delimiter that separates items
) RETURNS #List TABLE (SplitValue VARCHAR(max))
BEGIN
DECLARE #sItem VARCHAR(max)
WHILE CHARINDEX(#sDelimiter,#sInputList,0) <> 0
BEGIN
SELECT
#sItem=RTRIM(LTRIM(SUBSTRING(#sInputList,1,CHARINDEX(#sDelimiter,#sInputList,0)-1))),
#sInputList=RTRIM(LTRIM(SUBSTRING(#sInputList,CHARINDEX(#sDelimiter,#sInputList,0)+LEN(#sDelimiter),LEN(#sInputList))))
IF LEN(#sItem) > 0
INSERT INTO #List SELECT #sItem
END
IF LEN(#sInputList) > 0
INSERT INTO #List SELECT #sInputList -- Put the last item in
RETURN
END
And then write your query like this.
select * from (
select SplitValue,ROW_NUMBER() over(order by SplitValue) rowNo FROM dbo.fnSplit('1,2,3',',')
) as a
full join (
select SplitValue,ROW_NUMBER() over(order by SplitValue) rowNo FROM dbo.fnSplit('4,5,6,7',',')
) as b on a.rowNo=b.rowNo
replace your column in hardcore string and. Note: You can also write with query instead of function.
Oracle
with r (id,monname,ip,policy,n,max_tokens)
as
(
select id,monname,ip,policy
,1
,greatest (nvl(regexp_count(ip,'[^,]+'),0),nvl(regexp_count(policy,'[^,]+'),0))
from tbl_commaseperate
union all
select id,monname,ip,policy
,n+1
,max_tokens
from r
where n < max_tokens
)
select r.id
,r.monname
,regexp_substr (ip ,'[^,]+',1,n) as ip
,regexp_substr (policy,'[^,]+',1,n) as policy
from r
;
CREATE TABLE #Table ( ID VARCHAR(100),MONNAME VARCHAR(100), IP VARCHAR(100) , POLICY VARCHAR(100))
INSERT INTO #Table (ID ,MONNAME, IP, POLICY)SELECT 'X','NOV',1,2,3,4','4,5,6,7'
;WITH _CTE ( _id ,_MONNAME , _IP , _POLICY , _RemIP , _RemPOLICY) AS (
SELECT ID ,MONNAME , SUBSTRING(IP,0,CHARINDEX(',',IP)), SUBSTRING(POLICY,0,CHARINDEX(',',POLICY)),
SUBSTRING(IP,CHARINDEX(',',IP)+1,LEN(IP)),
SUBSTRING(POLICY,CHARINDEX(',',POLICY)+1,LEN(POLICY))
FROM #Table
UNION ALL
SELECT _id ,_MONNAME , CASE WHEN CHARINDEX(',',_RemIP) = 0 THEN _RemIP ELSE
SUBSTRING(_RemIP,0,CHARINDEX(',',_RemIP)) END, CASE WHEN CHARINDEX(',',_RemPOLICY) = 0 THEN _RemPOLICY ELSE SUBSTRING(_RemPOLICY,0,CHARINDEX(',',_RemPOLICY)) END,
CASE WHEN CHARINDEX(',',_RemIP) = 0 THEN '' ELSE SUBSTRING(_RemIP,CHARINDEX(',',_RemIP)+1,LEN(_RemIP)) END,
CASE WHEN CHARINDEX(',',_RemPOLICY) = 0 THEN '' ELSE SUBSTRING(_RemPOLICY,CHARINDEX(',',_RemPOLICY)+1,LEN(_RemPOLICY)) END
FROM _CTE WHERE _RemIP <> '' OR _RemPOLICY <> ''
)
SELECT _id id,_MONNAME MONNAME, _IP IP , _POLICY POLICY
FROM _CTE

How to reduce the value of a column in a row with?

I have a table with two columns:
No Value
1 20
2 10
3 50
4 35
5 17
I also have a variable or parameter where the variables will reduce the value of a column in a row.
So, if my variable V = 5 then my column will update:
No Value
1 15
2 10
3 50
4 35
5 17
Or if V = 50 then:
No Value
1 0
2 0
3 30
4 35
5 17
How can I do that?
First prepare the structure and the data:
CREATE TABLE TAB
(
[No] int identity(1,1) primary key,
[Value] int
);
INSERT INTO TAB VALUES (20);
INSERT INTO TAB VALUES (10);
INSERT INTO TAB VALUES (50);
INSERT INTO TAB VALUES (35);
INSERT INTO TAB VALUES (17);
So now we define your variable to reduce the [Value]:
DECLARE #var int
SET #var = 5
And now you can query your table:
SELECT [No], CASE WHEN [Value] - #var < 0 THEN 0 ELSE [Value] - #var END AS [Value]
FROM TAB
Very easy. You can set your variable to 50 an try again.
Here is a fiddle for this example.
Use CTE can be one of the options
declare #Values table
(
[No] int identity(1,1) not null,
Value int not null
)
declare #DeductAmount int = 50
INSERT #Values VALUES (20), (10), (50), (35), (17)
;WITH cte AS
(
SELECT *,
#DeductAmount - CASE WHEN Value >= #DeductAmount THEN #DeductAmount ELSE Value END AS RemainDeductAmount,
Value - CASE WHEN Value >= #DeductAmount THEN #DeductAmount ELSE Value END DeductedValue
FROM #Values WHERE [No] = 1
UNION ALL
SELECT
v.*,
cte.RemainDeductAmount - CASE WHEN v.Value >= cte.RemainDeductAmount THEN cte.RemainDeductAmount ELSE v.Value END,
v.Value - CASE WHEN v.Value >= cte.RemainDeductAmount THEN cte.RemainDeductAmount ELSE v.Value END DeductedValue
FROM #Values v INNER JOIN cte ON v.[No] = cte.[No] + 1
)
UPDATE target SET Value = DeductedValue
FROM #Values target INNER JOIN cte ON target.[No] = cte.[No]
SELECT * FROM #Values
The secret inside the cte
No Value RemainDeductAmount DeductedValue
----------- ----------- ------------------ -------------
1 20 30 0
2 10 20 0
3 50 0 30
4 35 0 35
5 17 0 17
Change 50 with your variable
Query:
SELECT t.No,
CASE WHEN SUM(t.Value)over(ORDER BY t.No) - 50 <0 THEN 0
WHEN SUM(t2.Value)over(ORDER BY t2.No) > 50
AND SUM(t.Value)over(ORDER BY t.No) >50 THEN t.Value
ELSE SUM(t.Value)over(ORDER BY t.No) - 50
END AS Value
FROM Table1 t
LEFT JOIN Table1 t2 ON t.No - 1 = t2.No
Here is another version:
DECLARE #t TABLE(ID INT IDENTITY(1, 1) , v INT )
DECLARE #x INT = 5
INSERT INTO #t VALUES ( 20 ), ( 10 ), ( 50 ), ( 35 ), ( 17 );
WITH cte
AS ( SELECT * ,
#x - ( SELECT ISNULL(SUM(v), 0) AS v
FROM #t t2
WHERE t2.ID <= t1.ID) s
FROM #t t1
)
SELECT ID ,
CASE WHEN s >= 0 THEN 0
WHEN s < 0 AND v + s > 0 THEN -s
ELSE v END
FROM cte
DECLARE #qty int
SET #qty= 50
WHILE #qty> 0
BEGIN
SELECT #qty= #qty- value
FROM table
WHERE no = (SELECT MIN(no) FROM table WHERE value > 0)
IF #qty< 0
BEGIN
UPDATE table
SET value = ABS(#qty)
WHERE (SELECT MIN(no) FROM table WHERE value > 0)
END
ELSE
BEGIN
UPDATE table
SET value = 0
WHERE (SELECT MIN(no) FROM table WHERE value > 0)
END
END

T-SQL How to select min, max and first row from table from duplicate values

DateTime -- Unit -- Client --- Qty
03/02/2013 08:00:01 -- 3 -- 1 --- 1
03/02/2013 08:00:02 -- 3 -- 2 --- 1
03/02/2013 08:00:03 -- 3 -- 3 --- 2
03/02/2013 08:00:04 -- 3 -- 3 --- 2
03/02/2013 08:00:05 -- 3 -- 3 --- 5
03/02/2013 08:00:06 -- 3 -- 3 --- 4
03/02/2013 08:00:07 -- 3 -- 4 --- 6
03/02/2013 08:00:08 -- 3 -- 4 --- 67
03/02/2013 08:00:09 -- 3 -- 4 --- 76
03/02/2013 08:00:10 -- 3 -- 4 --- 76
And I want :
DateTime -- Unit -- Client --- Qty
03/02/2013 08:00:01 -- 3 -- 1 --- 1
03/02/2013 08:00:02 -- 3 -- 2 --- 1
03/02/2013 08:00:03 -- 3 -- 3 --- 2
03/02/2013 08:00:05 -- 3 -- 3 --- 5
03/02/2013 08:00:07 -- 3 -- 4 --- 6
03/02/2013 08:00:09 -- 3 -- 4 --- 76
The criteria to filter is get the min and max "Qty" from table and get only the first value when exists duplicate "Qty" values in the same "Unit" and "client" column.
I do the follow T-SQL, but the retrieval is the last "Qty" value when the "Unit" and "client" column are the same, I need the first.
--1
CREATE TABLE Transact
(DateTime DateTime,
Unit INT NULL,
Client INT NULL,
Qty INT NULL
)
INSERT INTO Transact (Datetime,Unit,Client,Qty)
Values ( '03/02/2013 08:00:01',3,1,1)
Values ( '03/02/2013 08:00:02',3,2,1)
Values ( '03/02/2013 08:00:03',3,3,2)
Values ( '03/02/2013 08:00:04',3,3,2)
Values ( '03/02/2013 08:00:05',3,3,5)
Values ( '03/02/2013 08:00:06',3,3,4)
Values ( '03/02/2013 08:00:07',3,4,6)
Values ( '03/02/2013 08:00:08',3,4,67)
Values ( '03/02/2013 08:00:09',3,4,76)
Values ( '03/02/2013 08:00:10',3,4,76)
DECLARE #Total TABLE
(DateTime DateTime,
Unit INT NULL,
Client INT NULL,
Qty INT NULL
)
DECLARE #Uniques TABLE
(DateTime DateTime,
Unit INT NULL,
Client INT NULL,
Qty INT NULL
)
DECLARE #Mini TABLE
(DateTime DateTime,
Unit INT NULL,
Client INT NULL,
Qty INT NULL
)
DECLARE #Maxi TABLE
(DateTime DateTime,
Unit INT NULL,
Client INT NULL,
Qty INT NULL
)
--2
INSERT INTO #Total SELECT * FROM Transact
INSERT INTO #Mini SELECT MIN(Datetime) Datetime,Unit,Client,MIN(Qty) FROM #Total GROUP BY Unit,Client
INSERT INTO #Maxi SELECT MAX(Datetime) Datetime,Unit,Client,MAX(Qty) FROM #Total GROUP BY Unit,Client
--3
INSERT INTO #Uniques SELECT * FROM #Mini UNION SELECT * FROM #Maxi
SELECT * FROM #Uniques
Thanks in advance.
Pablo Geronimo.
Try this:
WITH MinCTE
AS
(
SELECT *,
ROW_NUMBER() OVER(Unit, PARTITION BY Client
ORDER BY Qty, DateTime ) AS RN
FROM Transact
), MaxCTE
AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY Unit, Client
ORDER BY Qty DESC, DateTime) AS RN
FROM Transact
)
SELECT DateTime, Unit, Client, Qty FROM MinCTE WhERE RN = 1
UNION
SELECT DateTime, Unit, Client, Qty FROM MaxCTE WhERE RN = 1;
SQL Fiddle demo
Here's what you can try:
SELECT DISTINCT MIN(DateTime), MIN(Qty), Unit, Client FROM Transact
GROUP BY Unit, Client
UNION
SELECT DISTINCT MAX(DateTime), MAX(Qty), Unit, Client FROM Transact
GROUP BY Unit, Client
First select the records with min and max Qty to a single table, and then select the min DateTime for those records.
SELECT MIN(DateTime), [Transact].Unit, [Transact].Client, [Transact].Qty
FROM (
SELECT DISTINCT Unit, Client, MIN(Qty) as Qty
FROM [Transact]
GROUP BY Unit, Client
UNION
SELECT Unit, Client, MAX(Qty)
FROM [Transact]
GROUP BY Unit, Client
) as MinMax
JOIN [Transact] ON [Transact].Unit = MinMax.Unit AND [Transact].Client = MinMax.Client AND [Transact].Qty = MinMax.Qty
GROUP BY [Transact].Unit, [Transact].Client, [Transact].Qty
I used a subquery but isn’t hard to change it to a memory table if you prefer.

Get MAX value of a BIT column

I have a SELECT request with 'inner join' in the joined table is a column with bit type.
I want to select 1 if in the joined table is at most one value with 1. If it is not the case the value will be 0.
So If I have:
PERSID | NAME
1 | Toto
2 | Titi
3 | Tata
And the second table
PERSID | BOOL
1 | 0
1 | 0
2 | 0
2 | 1
I would like to have for result
Toto -> 0
Titi -> 1
Tata -> 0
I try this:
SELECT
sur.*
,MAX(bo.BOOL)
FROM SURNAME sur
INNER JOIN BOOL bo
ON bo.IDPERS = sur.IDPERS
But MAX is not available on BIT column.. So how can I do that?
Thanks,
you can cast it to an INT, and even cast it back to a BIT if you need to
SELECT
sur.*
,CAST(MAX(CAST(bo.BOOL as INT)) AS BIT)
FROM SURNAME sur
INNER JOIN BOOL bo
ON bo.IDPERS = sur.IDPERS
Try:
max(cast(bo.BOOL as int))
One way
SELECT
sur.*
,MAX(convert(tinyint,bo.BOOL))
FROM SURNAME sur
INNER JOIN BOOL bo
ON bo.IDPERS = sur.IDPERS
You can avoid the messy looking double cast by forcing an implicit cast:
SELECT
sur.*
,CAST(MAX(1 * bo.BOOL) AS BIT)
FROM SURNAME sur
INNER JOIN BOOL bo
ON bo.IDPERS = sur.IDPERS
If you want only those people with exactly one set bit:
declare #Surname as Table ( PersId Int, Name VarChar(10) )
insert into #Surname ( PersId, Name ) values
( 1, 'Toto' ), ( 2, 'Titi' ), ( 3, 'Tata' ), ( 4, 'Tutu' )
declare #Bool as Table ( PersId Int, Bool Bit )
insert into #Bool ( PersId, Bool ) values
( 1, 0 ), ( 1, 0 ),
( 2, 0 ), ( 2, 1 ),
( 4, 1 ), ( 4, 0 ), ( 4, 1 )
select Sur.PersId, Sur.Name, Sum( Cast( Bo.Bool as Int ) ) as [Sum],
case Sum( Cast( Bo.Bool as Int ) )
when 1 then 1
else 0
end as [Only One]
from #Surname as Sur left outer join
#Bool as Bo on Bo.PersId = Sur.PersId
group by Sur.PersId, Sur.Name
order by Sur.Name

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