Aggregate function with where clause - sql-server

I have a situation where I need the aggregate function to be use in the where condition for the update
statement and also for select statement.
Example:
Situation 1:
Update test_table
set ID_Number = 0
where count(ID_Number)=1; /* Not possible with where */
Note: Above script is not possible with where clause.
Situation 2:
For example I have the following table: Test
ID_Number Column1 Column2
--------------------------
1 XYZ ZYX
1 MMM NNN
2 III JJJ
3 AAA BBB
3 CCC DDD
Now I need to show only those records who's ID_Number is appear two times.
Expected Result:
ID_Number Column1 Column2
------------------------------
1 XYZ ZYX
1 MMM NNN
3 AAA BBB
3 CCC DDD
My try:
select * from Test
group by ID_Number,Column1,Column2
having count(ID_Number)>1;
Note: This gives me nothing in result.

SET NOCOUNT ON;
DECLARE #Test TABLE
(
ID_Number INT NOT NULL,
Column1 VARCHAR(50),
Column2 VARCHAR(50)
);
INSERT INTO #Test VALUES (1, 'XYZ', 'ZYX');
INSERT INTO #Test VALUES (1, 'MMM', 'NNN');
INSERT INTO #Test VALUES (2, 'III', 'JJJ');
INSERT INTO #Test VALUES (3, 'AAA', 'BBB');
INSERT INTO #Test VALUES (3, 'CCC', 'DDD');
-- Situation #1
;WITH cte AS
(
SELECT ID_Number
FROM #Test
GROUP BY ID_Number
HAVING COUNT(*) = 1
)
UPDATE ts
SET ts.ID_Number = 0
FROM #Test ts
INNER JOIN cte
ON cte.ID_Number = ts.ID_Number;
-- Situation #2
;WITH cte AS
(
SELECT ID_Number
FROM #Test
GROUP BY ID_Number
HAVING COUNT(*) > 1
)
SELECT ts.*
FROM #Test ts
INNER JOIN cte
ON cte.ID_Number = ts.ID_Number;
The output is the "Expected Result" shown in the question.
For both situations, the CTE gets the ID_Number values that show up more than once, and that list of values is used to filter the main SELECT or UPDATE.

First looking to your Situation 2 your query to getting your desired output will be as follows:
SELECT * FROM Test
WHERE ID_Number IN (select ID_Number from Test
group by ID_Number
having count(ID_Number)>1)
Now looking to your Situation 1 you can write UPDATE query which updates columns
: ID_Number = 0 to only those records whose ID_Number records coming once as per you stated in your Update query. You can modify your update query as follows:
Update test_table
set ID_Number = 0
FROM test_table
WHERE ID_Number IN (select ID_Number from Test
group by ID_Number
having count(ID_Number) = 1

try this:
Situation 1:
For Updating Your Can USE Common Table Expressions
Update test_table
set ID_Number = 0
where ID_Number IN (
select tst.ID_Number from test_table tst join
(
select ID_Number,COUNT(*) as CNT from test_table
GROUP BY ID_Number)d
ON d.ID_Number=tst.ID_Number
where d.CNT=1
)
Situation 2:
select tst.ID_Number,Column1,Column2 from test_table tst join
(
select ID_Number,COUNT(*) as CNT from test_table
GROUP BY ID_Number)d
ON d.ID_Number=tst.ID_Number
where d.CNT>1
SQL Fiddle

Here's what I'd do:
with cte as (
select *, count(*) over (partition by ID_Number) as c
from test_table
)
select *
from cte
where c > 1

Related

Replacing a single column with randomly selected values from another table

I found some solutions to replace (below example) #test.col2 with data from #test2.src. But in the result it just selects a single random value and replaces them all with it. How to fix? Thanks!
#test (the target table)
col1 col2
-------------
A 1
B 2
C 3
D 4
E 5
#test2 (the source table)
src1
sample1
sample2
sample3
Query:
UPDATE #test
SET col1 = data1.LastName
FROM #test
CROSS APPLY
(SELECT TOP(1) #test2.LastName
FROM #test2
ORDER BY NEWID()) data1
Example result:
col1 col2
----------------
A sample2
B sample2
C sample2
D sample2
E sample2
Here is one way to tackle this. It is using ROW_NUMBER in a cte to "randomize" the values.
if OBJECT_ID('tempdb..#test') is not null
drop table #test;
create table #test
(
col1 varchar(20)
, col2 int
);
insert #test
select 'A', 1 union all
select 'B', 2 union all
select 'C', 3 union all
select 'D', 4 union all
select 'E', 5;
if OBJECT_ID('tempdb..#test2') is not null
drop table #test2;
create table #test2
(
LastName varchar(20)
);
insert #test2
select 'src1' union all
select 'sample1' union all
select 'sample2' union all
select 'sample3';
--here is the data before any updates
select * from #test;
with t1 as
(
select col1
, col2
, RowNum = ROW_NUMBER() over(order by newid())
from #test
)
, t2 as
(
select LastName
, RowNum = ROW_NUMBER() over(order by newid())
from #test2
)
update t
set col1 = t2.LastName
from t1
join t2 on t1.RowNum = t2.RowNum
join #test t on t.col1 = t1.col1
--we now have updated with a "random" row
select * from #test;

Count how many times a word exist in column

I have a table 1:
CREATE TABLE table1
INSERT INTO table1 values('XYZ')
INSERT INTO table1 values('ABC')
INSERT INTO table1 values('XYZ~ABC~AAA')
INSERT INTO table1 values('123')
Then, I have string 'ABC~XYZ~123'. I need to split this string into each word by using SQL:
Select VALUE FROM STRING_SPLIT('ABC~XYZ~123','~')
The return is table2
ABC
XYZ
123
I want to count how many times each word in table2 existed in table 1
The expected output is
ABC|3
XYZ|2
123|1
Any ideas on this?
If I understand your case correctly, the next statement may help:
Text and table:
DECLARE #text varchar(100) = 'ABC~XYZ~123'
CREATE TABLE Data (
Id int,
[Text] varchar(100)
)
INSERT INTO Data
(Id, [Text])
VALUES
(1, 'XYZ'),
(2, 'ABC'),
(3, 'XYZ~ABC~AAA'),
(4, '123~ABC')
Statement:
SELECT t.[value] AS [Word], j.[Count]
FROM STRING_SPLIT(#text, '~') t
LEFT JOIN (
SELECT s.[value], COUNT(*) AS [Count]
FROM Data d
CROSS APPLY STRING_SPLIT(d.[Text], '~') s
GROUP BY s.[value]
) j ON t.[value] = j.[value]
Result:
-----------
Word Count
-----------
ABC 3
XYZ 2
123 1
Apart from the suggestions as in comment you can use Count() function as below. But storing in this format will give you difficulty for the extraction as well as in join with the other tables.
Select T1Value, Count(*) as [NoCount] from(
Select table1.Value as T1Value, Value FROM STRING_SPLIT('ABC~XYZ~123','~')
inner join table1 on Value = table1.Value
)a group by T1Value
Edit
CREATE TABLE table1(
TableValue varchar(max)
);
INSERT INTO table1 (TableValue) values ( 'XYZ');
INSERT INTO table1 ( TableValue) values ( 'ABC');
INSERT INTO table1 ( TableValue) values ( 'XYZ~ABC~AAA');
INSERT INTO table1 ( TableValue) values ( '123~ABC');
SELECT b.value
,Count(*)
FROM (
SELECT VALUE
FROM STRING_SPLIT('ABC~XYZ~123', '~')
) a
INNER JOIN (
SELECT *
FROM table1
CROSS APPLY STRING_SPLIT(TableValue, '~')
) b ON a.Value = b.Value
GROUP BY b.Value
Here is the given Live Demo on db <> fiddle
Setup
create table STRINGS (ID int, STRINGS varchar(max));
insert into STRINGS (ID, STRINGS) values (1, 'XYZ');
insert into STRINGS (ID, STRINGS) values (1, 'ABC');
insert into STRINGS (ID, STRINGS) values (1, 'XYZ~ABC~AAA');
insert into STRINGS (ID, STRINGS) values (1, '123~ABC');
declare #VALUES varchar(max) = 'XYZ~ABC~123';
Calculation :
select V1.VALUE, count(STRINGS.ID)
from string_split(#VALUES,'~') V1
cross join STRINGS
outer apply string_split(STRINGS.STRINGS,'~') V2
where V2.VALUE = V1.VALUE
group by V1.VALUE
Result
-----------
Value Num
-----------
ABC 3
XYZ 2
123 1
Live exemple :
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=15b95efcf69ea98fafbb7dda1c624551

SQL Server: How to select missing rows in table from another table?

I have two tables like below:
table1:
StoreId SKU
------------
1 abc
2 abc
3 abc
1 xyz
4 xyz
table2:
StoreId
--------
1
2
3
4
5
I want to select missing storeid from the table1 which are in table 2. But condition is that in above example for SKU abc storeid 4 and 5 are missing and for sku xyz 2,3,5 are missing. So I want below table as output
SKU,ID
------
abc 4
abc 5
xyz 2
xyz 3
xyz 5
I am able to pull only the overall missing store which is 5 using below query.
SELECT
SKU, t2.StoreId
FROM
#table1 t1
FULL OUTER JOIN
#table2 t2 ON t1.StoreId = t2.StoreId
WHERE
t1.StoreId IS NULL
Below is test create and insert query.
Declare #table1 As table
(
StoreId varchar(4),
SKU varchar(5)
)
Declare #table2 As table
(
StoreId int
)
BEGIN
Insert Into #table1(SKU,StoreId) values('abc',1)
Insert Into #table1(SKU,StoreId) values('abc',2)
Insert Into #table1(SKU,StoreId) values('abc',3)
Insert Into #table1(SKU,StoreId) values('xyz',1)
Insert Into #table1(SKU,StoreId) values('xyz',4)
Insert Into #table2(StoreId) values(1)
Insert Into #table2(StoreId) values(2)
Insert Into #table2(StoreId) values(3)
Insert Into #table2(StoreId) values(4)
Insert Into #table2(StoreId) values(5)
END
Thank you
You need to get a list of all skus and tables, and then show only rows which do not appear in table1:
select SKU, StoreID
from #table2 t2
cross join (select distinct sku from #table1) t1
where not exists (select 1 from #table1 table1
where table1.SKU = t1.SKU
and table1.StoreId = t2.StoreId)
Here is an alternative solution with the same result.
Syntax is very similar to the answer from #BeanFrog:
SELECT
t3.SKU, t2.StoreID
FROM
#table2 t2
CROSS JOIN
(SELECT distinct SKU
FROM #table1) t3
LEFT JOIN
#table1 t1
ON
t1.SKU = t3.SKU
and t1.StoreId = t2.StoreId
WHERE
t1.sku is null

Updating Sql Server Row with increasing ID

How do I update sql server with increasing ID according to another column?
I have a table with following structure:
sn name val
test 0
test 0.5
test 2
test1 0
test1 0.5
test1 2
How do i update it so that is will be:
sn name val
1 test 0
2 test 0.5
3 test 2
1 test1 0
2 test1 0.5
3 test1 2
fiddle
Use cte and row_number
Here is an example :
create table #mytable (sn int, name varchar(20), val money)
insert into #mytable values (null, 'test', 0.5)
insert into #mytable values (null, 'test', 1)
insert into #mytable values (null, 'test1', 0.5)
insert into #mytable values (null, 'test1', 1)
;with cte as (select row_number() over (order by name, val) as rn, * from #mytable)
update cte set sn = rn
select * from #mytable
This can easily be done using Row_Number() and the OVER ... PARTITION BY clause, if you have a key column in the table. I added a column: Id int identity primary key and here's the update:
;with RowNumberedData as (
select
id,
row_number() over (
partition by name
order by id
) as rowno
from sql_test
)
update s
set sn = r.rowno
from sql_test s
join RowNumberedData r
on s.id = r.id;
SQLFiddle: http://sqlfiddle.com/#!3/43fa8/4
You should use ROW_NUMBER() function. Also as soon as you have to start new counter for each NAME value you should use PARTITON by NAME in this statement.
WITH T AS
(select sql_test.*,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Val) as RowNumber
from sql_test)
UPDATE T SET SN=RowNumber;
SQLFiddle demo

Check if table does not have records then insert 3 records in table

I want to Check if table does not have records then only insert 3 records in table for sql server as well as oracle.
This sort of construct will work in SQL Server and Oracle:
SQL> insert into t34
2 select * from emp where id <= 3
3 and 0 in ( select count(*) from t34 )
4 /
3 rows created.
SQL> r
1 insert into t34
2 select * from emp where rownum <= 3
3* and 0 in ( select count(*) from t34 )
0 rows created.
SQL>
But whether it can solve your problem really depends on the source of your three rows.
what was the problem with doing this ..
try from your part..
int count = select count(*) from table-name;
if(count==0){
//your insert statements as many as
insert into table-name values();
}
You just need to do something like this:
IF (Select count(*) from tablename) = 0
BEGIN
-- INSERT VALUES
END
if you want to insert values in a single insert sentence you can do like this:
insert into yourTable (yourFields)
select value1 as yourField1, ...
where (select count(*) from yourTable ) =0
Testing:
create table #t (k int);
insert into #t
select 1
where (select count(*) from #t ) =0
insert into #t
select 2 as k;
insert into #t
select 3
where (select count(*) from #t ) =0
select * from #t;
Notice that only '1' and '2' are inserted, not '3'.

Resources