Refer to previous computed column in SQL - sql

I am trying to calculate the val column using id column and the previous val column. On Excel, I simply use the formula "=IF(B2=1,1,C1+B2)". How can i reference previous value of my column being computed?
id val
1 1
2 3
3 6
4 10
5 15
6 21
7 28
8 36
9 45
10 55
My query would look like
SELECT id,
Case
When id =1 then 1
Else id+*previousval*
end as val
from
tab

It is better if you can tag your DBMS and its version..
Assuming that you are using SQL Server:
SQL Server BELOW 2012 (you can use the Common Table Expression - CTE)
CREATE TABLE #TEST(ID INT)
INSERT INTO #TEST VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
;WITH CTE
as
(
SELECT ID, ID AS VALUE FROM #TEST WHERE ID=1
UNION ALL
SELECT T.ID, T.ID + C.VALUE
FROM #TEST T INNER JOIN CTE C ON T.ID = C.ID+1
)
SELECT * FROM CTE
DROP TABLE #TEST
SQL Fiddle for version 2012 Below
SQL Server 2012: (you can use OVER clause)
CREATE TABLE #Test(ID INT)
INSERT INTO #Test VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
SELECT id, SUM(id) OVER(ORDER BY id) AS [Value] FROM #Test ORDER BY id
DROP TABLE #Test
SQL Fiddle: SQL Server 2012

You can try this solution for SQL Server (using variable will give you a best performance):
DECLARE #TempTable TABLE (Id INT, Val INT)
INSERT INTO #TempTable VALUES(1,0)
INSERT INTO #TempTable VALUES(2,0)
INSERT INTO #TempTable VALUES(3,0)
INSERT INTO #TempTable VALUES(4,0)
INSERT INTO #TempTable VALUES(5,0)
INSERT INTO #TempTable VALUES(6,0)
INSERT INTO #TempTable VALUES(7,0)
DECLARE #PrevSum INT = 0
UPDATE #TempTable
SET #PrevSum = Val = #PrevSum + Id
FROM #TempTable
SELECT * FROM #TempTable

Related

Add empty rows to results

I want to add empty rows to results fetched from a select statement. For example, if the select query fetch 4 rows then 2 empty rows needs to be fetched. Objective should be the number of rows fetched should be 6 every time. The number of rows fetched will be 6 maximum if there are 6 rows with data.
Any idea?
In SQL-SERVER You can create temp table to update It with empty rows and you can use WHILE to insert desired number of rows with empty values. Something like:
-- Create temp table to update data with empty rows
CREATE TABLE #HoldEmptyRows
(
Id NVARCHAR(20),
CustomerName NVARCHAR(20),
CustomerEmail NVARCHAR(20)
)
-- Insert data from SourceTable to temp
INSERT INTO #HoldEmptyRows
SELECT * FROM SourceTable
-- Do while count from temp table < of desired number insert empty rows
WHILE ((SELECT COUNT(*) cnt FROM #HoldEmptyRows) < 6)
BEGIN
INSERT INTO #HoldEmptyRows VALUES ('', '', '')
END
SELECT * FROM #HoldEmptyRows
DEMO AT SQL FIDDLE
Try the below logic:
with cte as
(
select 0 as col1
union all
select col1+1 from cte where cte.col1<10
)
select * into #temp1 from cte
create table #test
(rownum int,col1 varchar(100))
declare #i int=1
while (#i<=6)
begin
insert into #test
select * from
(select row_Number() over (order by (Select 0))rownum, * from #temp1)x
where rownum=#i
Set #i=#i+1
end
select case when rownum>4 then '' else col1 end as col1 from #test

Is there a way to return more than 1 row in select without using existing tables

Simple question, just out of curiosity.
For example select 1,2,3 that will show table with one column and three rows.
Something like this: select values(1),(2),(3)
*with one select statement
An example for my comment in your post.
DECLARE #TABLE TABLE (ONE INT, TWO INT, THREE INT)
INSERT INTO #TABLE VALUES (1,2,3)
SELECT UP.COL, UP.VALUE
FROM #TABLE
UNPIVOT (VALUE FOR COL IN (ONE,TWO,THREE)) UP
Query:
DECLARE #t TABLE (i1 INT, i2 INT, i3 INT)
INSERT INTO #t VALUES (1, 2, 3)
SELECT t.*
FROM #t
CROSS APPLY (
VALUES(i1), (i2), (i3)
) t(value)
Output:
value
-----------
1
2
3
Additional info:
http://blog.devart.com/is-unpivot-the-best-way-for-converting-columns-into-rows.html
As it appears there is a simple code that I've been searching for:
select n from (values (1),(2),(3)) D(c);

SQL Server sort column based on the same column itself

I have a db table containing a column display_order. The data looks like this:
2
4
7
10
12
I want to update the same db column and it should look like this:
1
2
3
4
5
Please suggest some easy SQL code.
Have a look into ROW_NUMBER(), this will help you here.
e.g. demo that won't update your data, but will show you the current order and the new order based on ROW_NUMBER
SELECT display_order AS CurrentDisplayOrder,
ROW_NUMBER() OVER (ORDER BY display_order) AS NewDisplayOrder
FROM YourTable
ORDER BY display_order
If that produces what you'd expect, then you can just switch it into an UPDATE statement.
Expanding on AdaTheDev's idea - using a CTE (Common Table Expression) makes it really easy to see how to use the actual UPDATE to update your table. I'm using a table variable #work here to simulate your existing table - just replace my table variable with your own table name:
DECLARE #work TABLE (display_order INT)
INSERT INTO #work VALUES(2)
INSERT INTO #work VALUES(4)
INSERT INTO #work VALUES(7)
INSERT INTO #work VALUES(10)
INSERT INTO #work VALUES(12)
SELECT * FROM #work
;WITH UpdateTable AS
(
SELECT
display_order, new_order = ROW_NUMBER() OVER (ORDER BY display_order)
FROM #work
)
UPDATE #work
SET display_order = u.new_order
FROM #work w
INNER JOIN UpdateTable u ON w.display_order = u.display_order
SELECT * FROM #work
Without CTE (but needs some key in the table)
declare #tbl table(id int primary key identity(1,1),Value int)
insert #tbl values(2)
insert #tbl values(5)
insert #tbl values(3)
select * from #tbl
select *, ROW_NUMBER() over(order by Value) from #tbl order by id
update #tbl set Value = result from #tbl tbl
inner join (select id, ROW_NUMBER() over(order by Value) result from #tbl ) hlp on tbl.id =hlp.ids
select * from #tbl

Any standard SQL expression to sort results base on IN expression [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
SQL - order by list order
Is there any standard SQL expression to sort results exactly base on IN expression. For example to return the results of the following query so that 2, 4, 6, 8 are returned serially?
SELECT * FROM SOMETABLE WHERE ID IN (2, 4, 6, 8)
The closest thing I can think of is doing a JOIN instead of an IN to a table with the original order with their ordinal rank
SELECT * FROM SOMETABLE INNER JOIN SOMETABLE2 ... etc
ORDER BY SOMETABLE2.original
If you have full controlled over your SQL rendering, then use a CASE expression:
ORDER BY CASE ID
-- render WHEN clauses in the desired order
WHEN 2 THEN 1
WHEN 4 THEN 2
WHEN 6 THEN 3
WHEN 8 THEN 4
END
Assuming you can pass the ids as a fixed delimited string, you can do the following :
-- Populate a number table
DECLARE #Temp Table(Number int)
INSERT INTO #Temp VALUES(1)
INSERT INTO #Temp VALUES(2)
INSERT INTO #Temp VALUES(3)
INSERT INTO #Temp VALUES(4)
INSERT INTO #Temp VALUES(5)
INSERT INTO #Temp VALUES(6)
INSERT INTO #Temp VALUES(7)
INSERT INTO #Temp VALUES(8)
INSERT INTO #Temp VALUES(9)
INSERT INTO #Temp VALUES(10)
SELECT TOP 8000 Number = IDENTITY(int,1,1) INTO [dbo].Numberos FROM #TEMP t1, #TEMP t2, #TEMP t3, #TEMP t4
ALTER TABLE [dbo].[Numbers] ADD CONSTRAINT [PK_Numbers] PRIMARY KEY CLUSTERED ([Number])
-- This function splits a fixed delimited string into a table object
CREATE FUNCTION [dbo].[fixstring_single](#str text, #itemlen tinyint)
RETURNS TABLE
AS
RETURN (SELECT listpos = n.Number,
str = substring(#str, (#itemlen + 1) * (n.Number - 1) + 1, #itemlen)
FROM Numbers n
WHERE n.Number <= (datalength(#str)+1) / (#itemlen+1))
DECLARE #ids varchar(100);
SET #ids = '00002 00001 00004';
-- Join to the number table ordered by the posisiton in the ids string
SELECT * FROM TestT INNER JOIN fixstring_single(#ids, 5) S ON TestT.ID = S.Str ORDER BY S.listpos

Query: find rows that do not belong to a list of values

Lets consider I have a table 'Tab' which has a column 'Col'
The table 'Tab' has this data -
Col
1
2
3
4
5
If I have a set of values (2,3,6,7). I can query the values that are present in the table and the list by suing the query
Select Col from Tab where col IN (2,3,6,7)
But, if I want to return the values in the list that are not present in the table i.e. only (6,7) in this case. What query should I use?
The problem I believe is that your trying to find values from you in statement. What you need to do is turn your in statement into a table and then you can determine which values are different.
create table #temp
(
value int
)
insert into #temp values 1
insert into #temp values 2
insert into #temp values 3
insert into #temp values 4
select
id
from
#temp
where
not exists (select 1 from Tab where Col = id)
A better alternative would be to create a table-valued function to turn your comma-delimited string into a table. I don't have any code handy, but it should be easy to find on Google. In that case you would only need to use the syntax below.
select
id
from
dbo.SplitStringToTable('2,3,6,7')
where
not exists (select 1 from Tab where Col = id)
Hope this helps
A SQL Server 2008 method
SELECT N FROM (VALUES(2),(3),(6),(7)) AS D (N)
EXCEPT
Select Col from Tab
Or SQL Server 2005
DECLARE #Values XML
SET #Values =
'<r>
<v>2</v>
<v>3</v>
<v>6</v>
<v>7</v>
</r>'
SELECT
vals.item.value('.[1]', 'INT') AS Val
FROM #Values.nodes('/r/v') vals(item)
EXCEPT
Select Col from Tab
one way would be to use a temp table:
DECLARE #t1 TABLE (i INT)
INSERT #t1 VALUES(2)
INSERT #t1 VALUES(3)
INSERT #t1 VALUES(6)
INSERT #t1 VALUES(7)
SELECT i FROM #t1 WHERE i NOT IN (Select Col from Tab)
One method is
declare #table table(col int)
insert into #table
select 1 union all
select 2 union all
select 3 union all
select 4 union all
select 5
declare #t table(col int)
insert into #t
select 2 union all
select 3 union all
select 6 union all
select 7
select t1.col from #t as t1 left join #table as t2 on t1.col=t2.col
where t2.col is null
Do you have a [numbers] table in your database? (See Why should I consider using an auxiliary numbers table?)
SELECT
[Tab].*
FROM
[numbers]
LEFT JOIN [Tab]
ON [numbers].[num] = [Tab].[Col]
WHERE
[numbers].[num] IN (2, 3, 6, 7)
AND [Tab].[Col] IS NULL
I think there are many ways to achive this, here is one.
SELECT a.col
FROM
(SELECT 2 AS col UNION ALL SELECT 3 UNION ALL SELECT 6 UNION ALL SELECT 7) AS a
WHERE a.col NOT IN (SELECT col FROM Tab)
Late to the party...
SELECT
'2s' = SUM(CASE WHEN Tab.Col = 2 THEN 1 ELSE 0 END),
'3s' = SUM(CASE WHEN Tab.Col = 3 THEN 1 ELSE 0 END),
'6s' = SUM(CASE WHEN Tab.Col = 6 THEN 1 ELSE 0 END),
'7s' = SUM(CASE WHEN Tab.Col = 7 THEN 1 ELSE 0 END)
FROM
(SELECT 1 AS Col, 'Nums' = 1 UNION SELECT 2 AS Col,'Nums' = 1 UNION SELECT 3 AS Col, 'Nums' = 1 UNION SELECT 4 AS Col, 'Nums' = 1 UNION SELECT 5 AS Col, 'Nums' = 1 ) AS Tab
GROUP BY Tab.Nums
BTW, mine also gives counts of each, useful if you need it. Like if you were checking a product list against what you have in inventory. Though you can write a pivot for that better, just don't know how off the top of my head.