countif type function in SQL where total count could be retrieved in other column - sql

I have 36 columns in a table but one of the columns have data multiple times like below
ID Name Ref
abcd john doe 123
1234 martina 100
123x brittany 123
ab12 joe 101
and i want results like
ID Name Ref cnt
abcd john doe 123 2
1234 martina 100 1
123x brittany 123 2
ab12 joe 101 1
as 123 has appeared twice i want it to show 2 in cnt column and so on

select ID, Name, Ref, (select count(ID) from [table] where Ref = A.Ref)
from [table] A
Edit:
As mentioned in comments below, this approach may not be the most efficient in all cases, but should be sufficient on reasonably small tables.
In my testing:
a table of 5,460 records and 976 distinct 'Ref' values returned in less than 1 second.
a table of 600,831 records and 8,335 distinct 'Ref' values returned in 6 seconds.
a table of 845,218 records and 15,147 distinct 'Ref' values returned in 13 seconds.

You should provide SQL brand to know capabilities:
1) If your DB supports window functions:
Select
*,
count(*) over ( partition by ref ) as cnt
from your_table
2) If not:
Select
T.*, G.cnt
from
( select * from your_table ) T inner join
( select count(*) as cnt from your_table group by ref ) G
on T.ref = G.ref

You can use COUNT with OVERin following:
QUERY
select ID,
Name,
ref,
count(ref) over (partition by ref) cnt
from #t t
SAMPLE DATA
create table #t
(
ID NVARCHAR(400),
Name NVARCHAR(400),
Ref INT
)
insert into #t values
('abcd','john doe', 123),
('1234','martina', 100),
('123x','brittany', 123),
('ab12','joe', 101)

Related

Move several columns to become rows

I have a table
Name Cost Total1
Joe 5 10
Bob 7 15
Tom 20 1
I want to more column Total1 and Total2 to become row for each record and expect result
Name Cost Total1
Joe 5
Joe 10
Bob 7
Bob 15
Tom 20
Tom 1
My query
select Name, cost, total1
indicatorname,
indicatorvalue
from mytable
unpivot
(
indicatorvalue
for indicatorname in (total1)
) unpiv;
I don't think it's working. Not sure how to maker it work. Thank you.
You can use a values constructor with cross apply to create split into multiple rows:
select T.name, v.Cost, v.Total1
from T cross apply (values
(1, Cost, null),
(2, null, Total1)
) v(n, Cost, Total1)
order by T.name, v.n;

Get custom column name while doing pivot in SQL Server

data set:
CREATE TABLE bank (
name varchar(255),
val int,
amount int
);
insert into bank values ('john',1,2000);
insert into bank values ('peter',1,1999);
insert into bank values ('peter',2,1854);
insert into bank values ('adi',1,1888);
Table Bank:
name val amount
--------------------
John 1 2000
Peter 1 1999
Peter 2 1854
adi 1 1888
pivoting using sum case:
SELECT name
,[1]
,[2]
FROM (
SELECT name
,val
,amount
FROM bank
) t
PIVOT(sum(amount) FOR Val IN (
[1]
,[2]
)) AS piv
output:
name amountval1 amountval2
-----------------------------
adi 1888 0
john 2000 0
peter 1999 1854
using pivot function:
select name ,[1],[2] from(
select name, val, amount from bank ) t
PIVOT (sum(amount) For Val in ([1],[2])) as piv
Output:
name 1 2
-----------------
adi 1888 NULL
john 2000 NULL
peter 1999 1854
Now the problem is I want to get the custom name i.e. amountval1 instead of 1 as i have done while using sum case. Can anyone help me get custom column name using pivot function?
It is a simple query and you don't need a sub-query or CTE:
just remember Pivot will rename the From table to Pivot Table [e.g. Col] :
select
name,
Col.[1] as amountval1,
Col.[2] as amountval2
from bank
PIVOT (sum(amount) For Val in ([1],[2])) Col
I generally recommend conditional aggregation in this case:
select name,
sum(case when val = 1 then amount else 0 end) as amountval1,
sum(case when val = 2 then amount else 0 end) as amountval2
from bank b
group by name;
This has several advantages in my opinion:
It uses standard SQL syntax.
It never requires a subquery -- even when bank has additional columns.
You can control the aggregation logic, so 0 is returned rather than NULL.
Renaming the columns is trivial.

Reconciliation Automation Query

I have one database and time to time i change some part of query as per requirement.
i want to keep record of results of both before and after result of these queries in one table and want to show queries which generate difference.
For Example,
Consider following table
emp_id country salary
---------------------
1 usa 1000
2 uk 2500
3 uk 1200
4 usa 3500
5 usa 4000
6 uk 1100
Now, my before query is :
Before Query:
select count(emp_id) as count,country from table where salary>2000 group by country;
Before Result:
count country
2 usa
1 uk
After Query:
select count(emp_id) as count,country from table where salary<2000 group by country;
After Query Result:
count country
2 uk
1 usa
My Final Result or Table I want is:
column 1 | column 2 | column 3 | column 4 |
2 usa 2 uk
1 uk 1 usa
...... but if query results are same than it shouldn't show in this table.
Thanks in advance.
I believe that you can use the same approach as here.
select t1.*, t2.* -- if you need specific columns without rn than you have to list them here
from
(
select t.*, row_number() over (order by count) rn
from
(
-- query #1
select count(emp_id) as count,country from table where salary>2000 group by country;
) t
) t1
full join
(
select t.*, row_number() over (order by count) rn
from
(
-- query #2
select count(emp_id) as count,country from table where salary<2000 group by country;
) t
) t2 on t1.rn = t2.rn

sql that identifies which account numbers have multiple agents

I dont think a count will work here, can someone help me get an sql that identifies which account numbers have multiple agents, more than two agents in the where condition.
AGENT_NAME ACCOUNT_NUMBER
Clemons, Tony 123
Cipollo, Michael 123
Jepsen, Sarah 567
Joanos, James 567
McMahon, Brian 890
Novak, Jason 437
Ralph, Melissa 197
Reitwiesner, John 221
Roman, Marlo 123
Rosenzweig, Marcie 890
Results should be something like this.
ACCOUNT_NUMBER AGENT_NAME
123 Cipollo, Michael
123 Roman, Marlo
123 Clemons, Tony
890 Rosenzweig, Marcie
890 McMahon, Brian
567 Joanos, James
567 Jepsen, Sarah
You can do this using window functions:
select t.account_number, t.agent_name
from (select t.*, min(agent_name) over (partition by account_number) as minan,
max(agent_name) over (partition by account_number) as maxan
from table t
) t
where minan <> maxan;
If you know the agent names are never duplicated, you could just do:
select t.account_number, t.agent_name
from (select t.*, count(*) over (partition by account_number) as cnt
from table t
) t
where cnt > 1;
Assuming your table name is test, this should pull all the records with duplicate ACCOUNT_NUMBER:
select * from test where ACCOUNT_NUMBER in
(select ACCOUNT_NUMBER from test
group by ACCOUNT_NUMBER having
count(ACCOUNT_NUMBER)>1)
order by ACCOUNT_NUMBER
Using count function u can get the result
CREATE TABLE #TEMP
(
AGENT_NAME VARCHAR(100),
ACCOUNT_NUMBER INT
)
INSERT INTO #TEMP
VALUES ('CLEMONS, TONY',123),
('CIPOLLO, MICHAEL',123),
('JEPSEN, SARAH',567),
('JOANOS, JAMES',567),
('MCMAHON, BRIAN',890),
('NOVAK, JASON',437),
('RALPH, MELISSA',197),
('REITWIESNER, JOHN',221),
('ROMAN, MARLO',123),
('ROSENZWEIG, MARCIE',890)
SELECT a.ACCOUNT_NUMBER,a.AGENT_NAME
FROM #TEMP A
JOIN(SELECT COUNT(1) CNT,
ACCOUNT_NUMBER
FROM #TEMP
GROUP BY ACCOUNT_NUMBER) B
ON A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER
WHERE B.CNT != 1

SQL Sort By a Column and group by another column simultaneously

Raw Table : Jobs
| Amount | Name |
3 Raj
1 Nish
15 Nish
10 Nish
8 Krish
22 Rahul
5 Raj
50 Raj
Required result format
| Amount | Name |
50 Raj
5 Raj
3 Raj
22 Rahul
15 Nish
10 Nish
1 Nish
8 Krish
The logic i am applying is sort the amount column and get the max amount i.e (50) and get
the other transaction of that person (Raj) and continue to search the second max item excluding the already selected person detail(excluding Raj).
Please help me with this
I Tried order by first "Amt" and then by "name" but it will not yield result as expected
This statement will give each name with its maximum amount.
select name, max(amount) as max_amt
from jobs
group by name
order by max_amt desc;
Raj 50
Nish 25
Rahul 22
Krish 8
Sorting on max_amt desc gives us the groups in the right order. Now all we need to do is join that to the "jobs" table, and sort the result by the two numerical columns.
I used a CTE to simplify things a bit.
with max_amounts as (
select name, max(amount) as max_amt
from jobs
group by name
)
select t1.*, t2.max_amt from jobs t1
inner join max_amounts t2
on t2.name = t1.name
order by max_amt desc, amount desc;
In standard SQL, I think you can just remove max_amt from the outer SELECT clause, and still use order by max_amt desc.
create table SORT_AMT_NAME(AMOUNT INT,NAME VARCHAR(20))
INSERT INTO SORT_AMT_NAME Values (22,'Rahul')
INSERT INTO SORT_AMT_NAME Values (8,'Krish')
INSERT INTO SORT_AMT_NAME Values (15,'Nish')
INSERT INTO SORT_AMT_NAME Values (1,'Nish')
INSERT INTO SORT_AMT_NAME Values (10,'Nish')
INSERT INTO SORT_AMT_NAME Values (50,'Raj')
INSERT INTO SORT_AMT_NAME Values (3,'Raj')
INSERT INTO SORT_AMT_NAME Values (5,'Raj')
INSERT INTO SORT_AMT_NAME Values (25,'GS')
SELECT AMOUNT,SORT_AMT_NAME.NAME FROM SORT_AMT_NAME,
(
select MAX(AMOUNT) AS MAX_AMT,NAME,ROW_NUMBER() over (order by MAX(AMOUNT) desc) as Amount_Order
from SORT_AMT_NAME
GROUP BY NAME) x
WHERE X.NAME=SORT_AMT_NAME.nAME
ORDER BY Amount_Order ASC ,AMOUNT DESC,SORT_AMT_NAME.NAME