Get detailed number of Rows affected by insert statement - sql

My table is setup with one of the columns named 'Month".
I run a sql insert statement on the table, and get the number of rows affected.
Is there a way to get the number of rows affected for each value of "Month"?
If my table is partition on the "Month" column, can that help?
My sql a standard one like follows:
INSERT INTO 'TargetTable'
(Column1, Column2, Months, Column4,....)
SELECT column_names
FROM SourceTable;
I'm using SqlCommand from .Net's SqlClient to pass the sql into SQL server.

A single insert statement returns a single rows affected count. You perform a separate insert for each value of 'month', so 12 insert statements instead of 1. That will have some performanc impact.
Alternatively, you could load the rows to be inserted into a temp table and do the insert and then report on things, something along these lines:
create table #work
( month int not null ,
primary_key_of_real_table int not null ,
)
insert #work
select t.month , t.primary_key_column
from source_table t
where -- your filter criteria here
insert target_table
( ... column list ... )
select ... column list ...
from #work t
join source_table x on x.primary_key_column =t.primary_key_of_real_table
select m.month , cnt = sum(case when t.month is null then 1 else 0 end)
from ( select month = 1 union all
select month = 2 union all
...
select month = 12
) m
left join #work t on t.month = m.month
group by t.month
order by t.month

Related

SQL - summarize results from multiple tables

I have the following simple SQL query that I need to run on 3 tables:
SELECT
A.date,
SUM(A.number)
FROM A
GROUP BY
A.date
But I have two other tables (B and C) on which I'd like to run the same query. And combine the results into one table as output.
I am expecting the output to look something like:
date
A.number
B.number
C.number
2022
12322.1
9999999
888888
We can try the following union approach:
SELECT
date,
SUM(CASE WHEN src = 'A' THEN number ELSE 0 END) AS A_sum,
SUM(CASE WHEN src = 'B' THEN number ELSE 0 END) AS B_sum,
SUM(CASE WHEN src = 'C' THEN number ELSE 0 END) AS C_sum
FROM
(
SELECT date, number, 'A' AS src FROM A
UNION ALL
SELECT date, number, 'B' FROM B
UNION ALL
SELECT date, number, 'C' FROM C
) t
GROUP BY date
ORDER BY date;
Here is my approach:
Create Table TableA
(
Dates Date,
Number Int
)
GO
Create Table TableB
(
Dates Date,
Number Int
)
GO
Create Table TableC
(
Dates Date,
Number Int
)
GO
Insert Into TableA
Values ('2023-01-01', 100000),
('2023-01-02',30000)
GO
Insert Into TableB
Values ('2023-01-01', 200000),
('2023-01-02',10000)
GO
Insert Into TableC
Values ('2023-01-01', 400000),
('2023-01-02',20000)
GO
SELECT * from
(
Select *,'A' Det from TableA
UNION ALL
Select *,'B' from TableB
UNION ALL
Select *,'C' from TableC
)ABC
PIVOT
(SUM(ABC.Number) FOR Det IN (A,B,C))
XYZ
DROP TABLE TableA
DROP Table TableB
DROP table TableC
IMO best option is to create calendar first and then left join created calendar with different tables:
Calendar is important to gather data from join.
And i'ts quite odd if you have column date as year.
In my oppinion it's to small level of complexity.
But ok. Let's say that you have only year.
Create table with years.
Create Table Years
(
years int
)
next:
INSERT INTO Years(years )
VALUES
(2022),(2021),(2020),(2019),(2018),(2017),(2016),(2015)
eg.
SELECT
y.*,
sum(a.number) as SumA,
sum(b.number) as SumB,
sum(c.number) as SumC
FROM Years as y
left join
table_a a
on
y.years=a.date
left join
table_b b
on
y.years=b.date
left join
table_c c
on
y.years=c.date
GROUP BY
y.years
Hopefully this helps!
Please let me know if it works as you wanted.

How to Limit the records

I have two tables called daily and master. Daily table is truncated every day but Master table holds the data and is never truncated. Every day I run a SQL script to merge the Daily table data with Master table as below inside a stored procedure:
UPDATE master
SET offset = COALESCE(offset + 1, 0);
MERGE INTO master m
USING daily d
ON (m.id = d.id)
WHEN MATCHED THEN
UPDATE SET offset = 0
WHEN NOT MATCHED THEN
INSERT (id, col1, col2, col3, offset)
VALUES (d.id, d.col1, d.col2, d.col3, NULL);
This works fine but in the WHEN NOT MATCHED clause, I need to Insert only a maximum of 100 records from Daily to Master. No there is no sorting criteria for the data to be inserted. How can I achieve this ?
You could use:
MERGE INTO master m
USING (
SELECT *
FROM (
SELECT d.*,
m.ROWID AS rid,
ROW_NUMBER() OVER (
PARTITION BY CASE WHEN m.ROWID IS NULL
THEN 'Insert'
ELSE 'Update'
END
ORDER BY ROWNUM
) AS rn
FROM daily d
LEFT OUTER JOIN master m
ON (m.id = d.id)
)
WHERE rid IS NOT NULL -- Update all rows.
OR rn <= 100 -- Only insert 100 rows.
) d
ON (m.ROWID = d.rid) -- Use the ROWID psuedo-column to join.
WHEN MATCHED THEN
UPDATE SET offset = 0
WHEN NOT MATCHED THEN
INSERT (id, col1, col2, col3, offset)
VALUES (d.id, d.col1, d.col2, d.col3, NULL);
db<>fiddle here
The main idea is to check the existence of the new records,which come from daily, whether exist within the table master or not as fetching all records from master while restricting them to 100 rows for the data coming from master.
use NVL2() function to determine the existence
filter non-existent data by using FETCH clause for 100 rows as using the database with version 12 without using an ORDER BY clause since you don't need any sorting criteria while fetching data.
So, replace the table name daily in your MERGE statement with the following subquery
(
WITH t AS
(
SELECT d.*, NVL2(m.id,1,0) AS exist
FROM daily d
LEFT JOIN master m
ON m.id = d.id
)
SELECT *
FROM t
WHERE exist = 1
UNION ALL
(SELECT *
FROM t
WHERE exist = 0
FETCH FIRST 100 ROWS ONLY)
)
Thank you #MT0 for the Demo

Counting repeated data

I'm trying to get maximum repeat of integer in table I tried many ways but could not make it work. The result I'm looking for is as:
"james";"108"
As this 108 when I concat of two fields loca+locb repeated two times but others did not I try below sqlfiddle link with sample table structure and the query I tried... sqlfiddle link
Query I tried is :
select * from (
select name,CONCAT(loca,locb),loca,locb
, row_number() over (partition by CONCAT(loca,locb) order by CONCAT(loca,locb) ) as att
from Table1
) tt
where att=1
please click here so you can see complete sample table and query I tried.
Edite: adding complete table structure and data:
CREATE TABLE Table1
(name varchar(50),loca int,locb int)
;
insert into Table1 values ('james',100,2);
insert into Table1 values ('james',100,3);
insert into Table1 values ('james',10,8);
insert into Table1 values ('james',10,8);
insert into Table1 values ('james',10,7);
insert into Table1 values ('james',10,6);
insert into Table1 values ('james',0,7);
insert into Table1 values ('james',10,0);
insert into Table1 values ('james',10);
insert into Table1 values ('james',10);
and what I'm looking for is to get (james,108) as that value is repeated two time in entire data, there is repetion of (james,10) but that have null value of loca so Zero value and Null value is to be ignored only those to be considered that have value in both(loca,locb).
SQL Fiddle
select distinct on (name) *
from (
select name, loca, locb, count(*) as total
from Table1
where loca is not null and locb is not null
group by 1,2,3
) s
order by name, total desc
WITH concat AS (
-- get concat values
SELECT name,concat(loca,locb) as merged
FROM table1 t1
WHERE t1.locb NOTNULL
AND t1.loca NOTNULL
), concat_count AS (
-- calculate count for concat values
SELECT name,merged,count(*) OVER (PARTITION BY name,merged) as merged_count
FROM concat
)
SELECT cc.name,cc.merged
FROM concat_count cc
WHERE cc.merged_count = (SELECT max(merged_count) FROM concat_count)
GROUP BY cc.name,cc.merged;
SqlFiddleDemo
select name,
newvalue
from (
select name,
CONCAT(loca,locb) newvalue,
COUNT(CONCAT(loca,locb)) as total,
row_number() over (order by COUNT(CONCAT(loca,locb)) desc) as att
from Table1
where loca is not null
and locb is not null
GROUP BY name, CONCAT(loca,locb)
) tt
where att=1

SQL Case statement with reference to different column in same row

I'm trying to write a select statement that identifies if a customer has signed up multiple times in the past 3 months while still providing all the data in the table I'm working from (example below)
I'm imaging the case query should look something like this but am do not know how to reference the row I want the result to populate in:
case when name in
(select name
from table1
where count(name from this row) > 1
and count(email from this row) > 1
and (date from this row) >= getdate()-120
end
table has 3 colums:
name, email, date
Any help?Thanks.
If you database is SQL Server 2005 or above then you can write a query as:
create table table1 (name varchar(20), email varchar(50), date datetime);
insert into table1 values ('Name1','email#abc.com',getdate()-30);
insert into table1 values ('Name1','email#abc.com',getdate()-60);
insert into table1 values ('Name1','email#abc.com',getdate());
insert into table1 values ('Name2','email2#abc.com',getdate()-20);
insert into table1 values ('Name3','email3#abc.com',getdate());
insert into table1 values ('Name4','email4#abc.com',getdate()-120);
with CTE as
(
select
row_number() over (partition by [name],[email] order by [name] asc) as rownum,
[name],
[email],
[date]
from table1
where [date] > = GETDATE() - 120
)
select * from CTE
where rownum > = 3

Using count as a condition in Oracle

I have two queries, q1 and q2. I want to return columns from q1 when q2 has no rows. Example:
select a, b, c from t1 where
count(select d, e, f from t2 where ...) == 0
and ...
Normally, I would just use a JOIN, but in this case, I have no related keys.
What is the best way to do this in Oracle?
I assume that those queries are entirely independant, like so:
create table table_q1 (
id number,
txt varchar2(10)
);
insert into table_q1 values ( 1, 'This');
insert into table_q1 values ( 2, 'data');
insert into table_q1 values ( 3, 'only');
insert into table_q1 values ( 4, 'selected');
insert into table_q1 values ( 5, 'if');
insert into table_q1 values ( 6, 'other');
insert into table_q1 values ( 7, 'query''s');
insert into table_q1 values ( 8, 'count');
insert into table_q1 values ( 9, 'greater');
insert into table_q1 values (10, 'zero');
create table table_q2 (
id number
);
insert into table_q2 values (1);
insert into table_q2 values (2);
insert into table_q2 values (3);
insert into table_q2 values (4);
You can now have a with-query q2 that selects the count of table_q2 and cross join it to table_q1 with the condition q2.cnt = 0 so that q1 only selects records if q2's count is != 0.
The following select statement returns no records:
with q2 as (select count(*) cnt from table_q2 where id > 2)
select q1.* from table_q1 q1, q2
where q2.cnt = 0
order by q1.id;
But this one does:
with q2 as (select count(*) cnt from table_q2 where id > 1000)
select q1.* from table_q1 q1, q2
where q2.cnt = 0
order by q1.id;
select <columns>
from table
where not exists (select <columns>
from table2
where ....)
should work. If there were some relationship between the inner query and the outer query, you would just add an additional predicate to the NOT EXISTS subquery that expressed that relationship (i.e. table.column_name = table2.column_name). But there is no need to make the subquery correlated.
You also don't need to specify the column names in the SELECT list of the subquery. It would only matter if adding the columns changed the query plan (say, by forcing the optimizer to query the table rather than using a covering index). You'll get the same result if you use something like this and it may be slightly faster.
select <columns>
from table
where not exists (select 1
from table2
where ....)
maybe you can try something like this
SELECT *
FROM TABLE1
WHERE DECODE((SELECT COUNT(T2.SOME_COLUMN)
FROM TABLE2 T2
WHERE T2.CONDITION_COLUMN = 'SOM_VAL'),
0,
'FALSE',
'TRUE') = 'TRUE'
Here the nested query within the DECODE will count the number of a certain column. In case it is ZERO, it will return false and query will return nothing or in case it returns anything more than ZERO, it will return TRUE and query will return values.
Hope it helps
Write a query that includes COUNT and GROUP BY without trying to filter out COUNT(x) = 0. You should see the zeros in your result set. That you want to eliminate.
Add a HAVING clause: HAVING COUNT(x) <> 0
If the tables are in fact joined on some field (let's name it id for both), it worth construct a query like
SELECT ... FROM table WHERE id NOT IN (SELECT id FROM table2 WHERE ...)
Check this query
Tested
select * from table1 where (SELECT count() FROM table2)=0