how to sum conditionally? - sql-server

I have a following table
Col1 Col2 Col3
A1 1 null
A1 2 null
B1 5 null
B2 6 null
M1 1 M
M2 2 M
M3 3 M
J1 1 J
J2 2 J
I want to sum Col2 based on Col1. The query will be like following,
select Col1, sum (Col2)
group by Col1
However, if Col3 has the same letter, I want sum up Col2 for all Col1. So the result table should be like
Col1 Col2
A1 3
B1 5
B2 6
M1 6
M2 6
M3 6
J1 3
J2 3
How do I change my query to get above table?

Edit after comment / update to question. I didn't know a clever way, seems like some others have one though.
select * from (
select Col1, SUM(Col2) Col2
from Table
where Col3 is null
group by Col1
union
select mainset.Col1, tmp.Col2
from Table mainset
join
(
select Col3, SUM(Col2) Col2
from Table
where Col3 is not null
group by Col3
) tmp on tmp.Col3 = mainset.Col3
where mainset.Col3 is not null
) fullset
order by fullset.Col1

You could do something like this (I named the table #a):
;WITH col3Sum AS
(
SELECT Col3, SUM(Col2) SUM3
FROM #a
WHERE col3 IS NOT NULL
GROUP BY col3
),
col1Sum AS
(
SELECT Col1, SUM(Col2) sum1
FROM #a
GROUP BY Col1
)
SELECT c1.Col1, ISNULL(c3.SUM3, c1.sum1) AS Col2
FROM col1Sum c1
LEFT JOIN col3Sum c3
ON c1.Col1 LIKE c3.Col3+'%'
ORDER BY c1.Col1

Related

SQL Server - Delete Duplicate Rows that based on different rows from another field

i have column and rows in my table as below
col0 col1 col2 col3 col4
----------------------------
1 A 1 100 AA
2 B 2 200 BB
3 B 1 100 AA
4 A 2 200 BB
i want the final result is
col0 col1 col2 col3 col4
----------------------------
1 A 1 100 AA
2 B 2 200 BB
OR
col0 col1 col2 col3 col4
----------------------------
3 B 1 100 AA
4 A 2 200 BB
i want to delete first and second rows OR third and fourth rows but based on col1, as you can see, their's not same with each other rows except with the col0, because the col0 is primary key. how should i do with sql server express 2012?
Here is an option for deleting the first pair of duplicate records. You can assign a row number based on a partition of the four data columns. Do this in a CTE, and then delete all records from that CTE where the row number is 1.
WITH cte AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY col2, col3, col4 ORDER BY col0) rn
FROM yourTable
)
DELETE
FROM cte
WHERE rn = 1
Follow the link below for a demo showing that the logic of my CTE is correct.
Demo
You can use this
DELETE FROM yourTable
WHERE col0 NOT IN ( SELECT MIN(col0) FROM yourTable GROUP BY col1)

Get values NOT IN Table1 when join with Table2

I have two tables as below:
Table1:
Col1 Col2
834 2
834 3
834 5
877 1
877 2
877 5
900 10
900 2
900 3
Table2:
Col3
1
10
Expected Output:
Col1 Col3
834 1
834 10
877 10
900 1
This is what I have done so far:
select distinct t1.Col1,A.Col3
from Table1
cross apply
(select * from Table2 left join Table1 on Col2 = Col3) A
order by t1.Col1,A.Col3
I have been trying lot using join, cross apply and other sql function to get me the expected output. Any help is appreciated.
Logic:
I want to get the values of Col1 of Table1 for which Col3 does not matches with col2 of Table1.
For Eg: Values 1 and 10 of Col3 of table2 is not there for value 834 of col1 of table1. Hence there are two rows for 834, one with value 1 and other with 10.
Please try with the below code snippet.
DECLARE #Table1 TABLE(
Col1 INT NOT NULL,
Col2 INT NOT NULL
);
INSERT INTO #Table1 VALUES(834 , 2)
INSERT INTO #Table1 VALUES(834 , 3)
INSERT INTO #Table1 VALUES(834 , 5)
INSERT INTO #Table1 VALUES(877 , 1)
INSERT INTO #Table1 VALUES(877 , 2)
INSERT INTO #Table1 VALUES(877 , 5)
INSERT INTO #Table1 VALUES(900 , 10)
INSERT INTO #Table1 VALUES(900 , 2)
INSERT INTO #Table1 VALUES(900 , 3)
DECLARE #Table2 TABLE(
Col3 INT NOT NULL
);
INSERT INTO #Table2 VALUES(1)
INSERT INTO #Table2 VALUES(10)
SELECT a.Col1,a.Col3 FROM (SELECT DISTINCT a.Col1,b.Col3 FROM #Table1 a,#Table2 b
WHERE a.Col2 <> b.Col3) a
LEFT JOIN #Table1 c on a.Col1 = c.Col1 and a.Col3 = c.Col2
WHERE c.Col1 is null
I doubt you need any join in here. All you want to select from table1 are the rows with matching value in table2. Something like this :
Select distinct col1, col2 from table1
Where col2 not in (select col3 from table2)
select a.col1, a.col2
from Table1 a
where not exists(select * from Table2 b where a.col1 = b.col3)
This may work...

SQL Server, count multiple columns

I have a table made like this:
Col1 Col2 Col3
____________________________
A AA AAA
A AA AAA
A AA BBB
B BB BBB
B AA CCC
What do i need is to count how many rows have the same combination of Col1 and Col2, like this:
Count Col1 Col2
_________________________
3 A AA
1 B BB
1 B AA
Just group by the columns and count the results:
SELECT COUNT(*) AS [COUNT], COL1, COL2
FROM YOUR_TABLE
GROUP BY COL1, COL2
Try this:
SELECT COUNT(*) as Count, COL1, COL2
FROM TableName
GROUP BY COL1, COL2
Result:
COUNT COL1 COL2
3 A AA
1 B AA
1 B BB
See result in SQL Fiddle.
COUNT returns the number of items in a group. Read more here.

Is there a T-SQL shortcut for getting the max values of two columns

What I mean is, say you have a table like:
Col1 Col2
---- ----
1 1
1 9
2 1
2 3
4 1
4 2
I want to get: Col1=4 and Col2=2, because Col1 has precendence. In other words, I want the largest value of Col1 and for that value the largest value of Col2 in a minimal T-SQL expression. It's almost like saying:
SELECT TOP 1 Col1, Col2
FROM MyTable
ORDER BY Col1, Col2 DESC
But doing this in such a way that the Col1, Col2 values are usable within another query.
Not really anything like MAX(Col1, Col2). If you wanted to simulate MAX ... GROUP BY X you could use
WITH T AS
(
SELECT Col1,
Col2,
ROW_NUMBER () OVER (PARTITION BY X ORDER BY Col1 DESC, Col2 DESC) AS RN
FROM MyTable
)
SELECT Col1,
Col2,
X
FROM T
WHERE RN= 1;
Like this? One row
SELECT ...
FROM
SOmeTable
JOIN
(
SELECT TOP 1 Col1, Col2
FROM MyTable
ORDER BY Col1, Col2 DESC
) foo ON S.Col1 = foo.Col1
Or per outer row?
SELECT ...
FROM
SOmeTable S
CROSS APPLY
(
SELECT TOP 1 Col2
FROM MyTable M
WHERE S.somecol = M.SomeCol
ORDER BY Col2 DESC
) foo
SELECT ...
FROM
SOmeTable S
CROSS APPLY
(
SELECT Col1, MAX(Col2) AS MaxCOl2
FROM MyTable M
GROUP BY Col1
) foo ON S.Col1 = foo.Col1
WITH t(Col1,maxCol1,maxCol2) AS (
SELECT
Col1,
MAX(Col1) OVER(),
MAX(Col2) OVER(PARTITION BY Col1)
)
SELECT TOP 1 maxCo11,maxCol2 FROM t WHERE Col1 = maxCol1

sqlserver running count

Imagine the below table as A
col1 col2 col3 rank
1 2 n 5
1 2 n 6
2 3 a 3
While inserting below records from table B to table A, the rank column valus should be keep incrementing if the same records inserts.
Records in table B which gonna insert into A are
col1 col2 col3
1 2 n
2 3 a
The desired output in table A after the above records are inserted is,
col1 col2 col3 rank
1 2 n 5
1 2 n 6
1 2 n 7
2 3 a 3
2 3 a 4
Please help me how to acheive this.Thanks.
If the record in B are unique, then you could use a query like this
--------------EDIT-------------------
If B can have multiple records, you can use row_number() funcion with partition
insert into TestA
select b.*,
(select max([rank]) from TestA where col1 = b.col1 and col2 = b.col2 and col3 = b.col3)
+ row_number()over (partition by col1, col2, col3 order by col1, col2,col3 asc) as N
from TestB b
--------------END EDIT-------------------
Note: i renamed the table: TestA and TestB
insert into TestA
select b.*, (select max([rank])+1 from TestAwhere col1 = b.col1 and col2 = b.col2 and col3 = b.col3)
from TestB b
or with a JOIN like this
insert into testa
select b.*, mr+1 from TestB b
join
(select col1, col2, col3, max([rank]) as mr
from TestA A
group by col1, col2, col3) as M
on
b.col1 = M.col1 and b.col2 = M.col2 and b.col3 =M.col3
I would use an INSTEAD OF INSERT trigger for this. Like this:
CREATE TRIGGER rankInsertTrigger
ON A
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO A(col1, col2, col3, rank)
SELECT i.col1, i.col2, i.col3,
MAX(SELECT a.rank
FROM A AS a
WHERE a.col1 = i.col1
AND a.col2 = i.col2
AND a.col3 = i.col3) + 1
FROM inserted i
END
Every time you now insert values into table A, this trigger runs and replaces the original insert with an insert that sets the rank you want.
For example, when you do INSERT INTO A(col1, col2, col3) VALUES (1, 2, n), what actually runs is the insert statement in the trigger (which takes the original values for col1, col2, col3 but overwrites rank).

Resources