Subtract 2 rows using case statement in SQL Server 2008 - sql

My data is like below, it's in a single table
Column1 Column2
abc 100
abc 200
Now I need like below
abc 100 //here 200-100
I am banging my head on how to achieve this.
I have tried to use the row_number and then subtract using case statement like
Select
column1,
sum(
case when rownum=1
then column2
end
-
case when rownum=2
then column2
end
)
from table
group by column1
But this is giving me null.

Assuming there is no attribute which can define row ordering -
;with cte as(
select
row_number() over (order by (select null)) as IndexId,
Column1,
Column2
from #xyz
)
select sum(case when IndexID=1 then (-1 * Column2) else Column2 end), Column1
from cte
group by Column1
Input data-
declare #xyz table(Column1 varchar(10),Column2 int)
insert into #xyz
select 'abc' ,100 union all
select 'abc' ,200

Assuming you have an attribute rownum in table which is always 1 or 2 (it can be generated by some row_number() as you suggest in question, according to any order that is suitable for you)
Column1 Column2 Rownum
------------------------
abc 100 1
abc 200 2
then you can simply use
Select
column1,
sum(
case when rownum=1
then column2
else -column2
end
)
from table
group by column1
It performs a sum of the Column2 per Column1, however, in the row having rownum = 2 the Column2 value is negated. Therefore in our example you end up with 100 + (-200) = -100

You could do:
select column1, max(column2) - min(column2)
from t
group by column1;

Here is a short form of the answer above if you care:
SELECT
column1,
SUM(IIF(rownum=1,column2,-column2))
FROM table
GROUP BY column1

Related

Select row after filter row has a coincident column in sql

I have a database as below
Column1 column2 column3
A123 abc Def
A123 xyz Abc
B456 Gh Ui
I want to select rows which don't have coincident content in column 1 by sql command.
In this case, The expected result is only row 3rd.
How to do it?
Thanks
you could use a join with a subselect for count =1
select * from my_table m
inner join (
select column1, count(*)
from my_table
group by column_1
having count(*) =1
) t on t.column_1 = m.column_1
WITH CTE AS (Select COUNT(Column1) OVER(PARTITION BY Column1 ) as coincident,* from table )Select * from CTE where coincident =1
I would use window functions:
select Column1, column2, column3
from (select t.*, count(*) over (partition by column1) as cnt
from t
) t
where cnt = 1;
However, there are other fun ways. For instance, aggregation:
select column1, max(column2) as column2, max(column3) as column3
from t
group by column1
having count(*) = 1;
Or if you know one of the other columns is going to have different values on different rows, then not exists may be the most efficient solution:
select t.*
from t
where not exists (select 1
from t t2
where t2.column1 = t.column1 and
t2.column2 <> t.column2
);

How to combine multiple columns into one column?

I'm writing a query and want the results in one column
My current results return like this
Column1 Column2 column3
1 A CAT
I want the results to return like this
Column1
1
A
CAT
SELECT Column1 FROM TableName
UNION ALL
SELECT Column2 FROM TableName
UNION ALL
SELECT Column3 FROM TableName
If you don't want duplicate values, use UNION instead of UNION ALL.
You can also do this using UNPIVOT operator
SELECT Column123
FROM
(
SELECT Column1, Column2, Column3
FROM TableName
) AS tmp
UNPIVOT
(
Column123 FOR ColumnAll IN (Column1, Column2, Column3)
) AS unpvt;
https://www.w3schools.com/sql/sql_union.asp
https://www.mssqltips.com/sqlservertip/3000/use-sql-servers-unpivot-operator-to-help-normalize-output/
The answer is.. it depends..
If the number of columns are unknown.. then use unpivot as UZI has suggested
if you know all columns and is a small finite set..
you can simply go
Select
column1
from table
union all
select column2
from table
union all
select column3
from table
The Cartesian product of the T table with derived table of 3 rows.(each row of #t is presented 3 times, for а=1 and а=2 and а=3). For the first case we take value from Column1,
and for the second - from Column2 and for the Third - from Column3.
Here, certainly, there is both union and join but, in my opinion, the title's question means single scanning the table.
CREATE TABLE #t (Column1 NVARCHAR(25),Column2 NVARCHAR(25), column3 NVARCHAR(25))
INSERT INTO #t
SELECT '1','A','CAT'
SELECT
CASE a WHEN 1 THEN Column1 WHEN 2 THEN Column2 ELSE column3 END col
FROM #t, (SELECT 1 a UNION ALL SELECT 2 UNION ALL SELECT 3) B
DROP TABLE #t

SQL Server : how to find ids where columns have different values

I have a table like this:
Column1 Column2
---------------
1 1
1 2
1 3
1 4
2 1
2 1
2 1
2 1
In column1 one there are 2 different ids, in column2 there are different values for each id from column1.
How can I get the id from column1 where not all ids from column2 are the same? So in this instance the output should be 1 - because they have all different values in column2, where id from column1 has all 1's in column2
Just use group by and having:
select column1
from table t
group by column1
having min(column2) <> max(column2);
Note: you could also use count(distinct), but that has more overhead than min() and max().
Similar logic can be used if the second column could be NULL. That doesn't appear in the sample data so it doesn't seem worth including it in the logic unless the OP specifically says this is a possibility.
Try like this:
select Column1
from yourTable
group by Column1
having count(DISTINCT column2) > 1;
I would think something like this should do the job:
SELECT t.column1 FROM table t
GROUP BY t.column1
HAVING COUNT(DISTINCT t.column2) > 1
This approach will handle the case where a null is an acceptable value in column2.
select column1
from
(
select distinct column1, column2
from yourTable
) t
group by column1
having count(*) > 1

SQL Count/Sum displaying column as rows

I have a table with 4 bit columns
I need to create a report that will show the total of all "true" values for each column but I need the column names to return as a row.
For examples, the table will contain:
Column1 Column2 Column3
1 1 0
0 1 0
1 1 0
The result should be:
Category Value
Column1 2
Column2 3
Column3 0
The table has other columns, I just need specific ones
Thanks
I don't know if there are other approaches, but the following should work:
select 'Column1' as "Category", sum(column1) as "Value" from my_table union
select 'Column2', sum(column2) from my_table union
select 'Column3', sum(column3) from my_table
Here's a SQLFiddle for it.
You can try UNPIVOT on the table (this is for SQL Server)
create table Test (Column1 bit, Column2 bit, Column3 bit)
insert into Test values (1,1,0)
insert into Test values (0,1,0)
insert into Test values (1,1,0)
SELECT Value, sum(Vals)
FROM
(CONVERT(INT, Column1) Column1, CONVERT(INT, Column2) Column2, CONVERT(INT, Column3) Column3
FROM Test) p
UNPIVOT
(Vals FOR Value IN
(Column1, Column2, Column3)
)AS unpvt
GROUP BY Value
PIVOT/UNPIVOT documentation
http://sqlfiddle.com/#!6/957c6/1/0
Try this:
select
category = "column1", value = sum (convert(int,col1)) from MyTable1
union
select
category = "column2", value = sum (convert(int,col2)) from MyTable1
union
select
category = "column3", value = sum (convert(int,col3)) from MyTable1

Sampling unique set of records in Oracle table

I have an Oracle table that from which I need to select a given percentage of records for each type of a given set of unique column combination.
For example,
SELECT distinct column1, column2, Column3 from TableX;
provides me all the combination of unique records from that table. I need a % of each rows from each such combination. Currently I am using the following query to accomplish this, which is lengthy and slow.
SELECT *
FROM tableX Sample ( 3 )
WHERE Column1 = ‘value1’ and
Column2 = ‘value2’ and
Column3 = ‘value3
UNION
SELECT *
FROM tableX Sample ( 3 )
WHERE Column1 = ‘value1’ and
Column2 = ‘value2’ and
Column3 = ‘value4
UNION
…
…
SELECT *
FROM tableX Sample ( 3 )
WHERE Column1 = ‘valueP’ and
Column2 = ‘valueQ’ and
Column3 = ‘valueR’
Where the combination of suffix in the “Value” is unique for that table (obtained from the first query)
How can I improve the length of the query and speed?
Here is one approach:
select t.*
from (select t.*,
row_number() over (partition by column1, column2, column3 order by dbms_random()
) as seqnum,
count(*) over (partition by column1, column2, column3) as totcnt
from tablex t
) t
where seqnum / totcnt <= 0.10 -- or whatever your threshold is
It uses row_number() to assign a sequential number to rows in each group, in a random order. The where clause chooses the proportion that you want.