How to Union Two Tables and Overwrite Preexisting Rows - sql-server

I want to combine two tables into one,
but if in table 1 the account code "Acc1" is the same as in table 2 the account code "Acc1"
then I want to take the amount in table 1 as the result
Table 1
Account Code AccountName Project Type Desc Period Amount
Bcc1 AccountBone AA Good PC2000 11/30/2022 700
Acc1 AccountOne AA Good PC2000 12/1/2022 300
Table 2
Account Code AccountName Project Type Desc Period Amount
Acc1 AccountOne AA Good PC2000 12/1/2022 220
Acc2 AccountOne AA Good PC2000 12/2/2022 432
Result
Account Code AccountName Project Type Desc Period Amount
Bcc1 AccountBone AA Good PC2000 11/30/2022 700
Acc1 AccountOne AA Good PC2000 12/1/2022 300
Acc2 AccountOne AA Good PC2000 12/2/2022 432
I was expecting a query for this case

One way would be a full outer join and an unpivoting technique to select the columns from T1 if there was a match or T2 otherwise (DB Fiddle)
SELECT CA.*
FROM Table1 t1
FULL JOIN Table2 t2
ON t1.AccountCode = t2.AccountCode
CROSS APPLY (SELECT t1.AccountCode,
t1.AccountName /*and other columns*/
WHERE t1.AccountCode IS NOT NULL
UNION ALL
SELECT t2.AccountCode,
t2.AccountName /*and other columns*/
WHERE t1.AccountCode IS NULL) CA

The question is a bit confusing. However, based on your results wouldn't this just work:
DROP TABLE IF EXISTS #TempTable1;
DROP TABLE IF EXISTS #TempTable2;
CREATE TABLE #TempTable1
(
AccountCode VARCHAR(100),
AccountName VARCHAR(100)
);
CREATE TABLE #TempTable2
(
AccountCode VARCHAR(100),
AccountName VARCHAR(100)
);
GO
INSERT INTO #TempTable1(AccountCode, AccountName)
VALUES('Bcc1', 'AccountBone'),
('Acc1', 'AccountOne');
INSERT INTO #TempTable2(AccountCode, AccountName)
VALUES('Acc1', 'AccountOne'),
('Acc2', 'AccountOne');
SELECT *
FROM #TempTable1
UNION
SELECT *
FROM #TempTable2;

You could select all from Table1 and from Table2 select all that do not exist in Table1:
select *
from Table1
union
select *
from Table2
where AccountCode not in (
select AccountCode
from Table1
)
See a dbfiddle

Related

Subtracting two columns from two different table with different data

i had this problem where i got two tables with different values.
TABLE 1:
Description Qty Amount
Proc 1 1 100
Proc 2 1 50
Proc 3 1 60
TABLE 2:
Description Payment
Proc 1 60
Proc 1 30
Proc 2 20
Proc 3 60
Proc 2 20
So, the result should be like:
Description Balance
Proc 1 10
Proc 2 40
Proc 3 0
How will i do this with select query? thanks.
I Already tried this code but it should first get the distinct rows of TABLE1 and sum distinct values from TABLE2 before subtracting the two tables.
SELECT FEESList.[Fee Description], sum(StudentBILLING.Quantity* StudentBILLING.Total- isnull(StudReceipts.Amount,0)) as Balance
FROM StudentBILLING INNER JOIN FEESList ON StudentBILLING.FeeID = FEESList.FeeID INNER JOIN SREGStudentInformation ON StudentBILLING.StudentID = SREGStudentInformation.ID INNER JOIN
SemesterList ON StudentBILLING.SemesterID = SemesterList.SemID INNER JOIN SchoolYear ON StudentBILLING.SYid = SchoolYear.[SY ID] FULL JOIN StudReceipts ON FEESList.FeeID = StudReceipts.FeeID
WHERE (SREGStudentInformation.[Student ID] = #StudentNumber) AND (SemesterList.[Sem.] = #Sem) AND (SchoolYear.[School Year] = #SchoolYear) AND
(FEESList.[Type of Fee] = 2) AND (StudentBILLING.Quantity* StudentBILLING.Total- ISNULL(StudReceipts.Amount,0))>0
GROUP BY FEESList.[Fee Description]
The result is from this;
Description Amount Payments
Proc 1 100 60
Proc 1 100 30
Proc 2 50 20
Proc 2 50 20
Proc 3 60 60
To this result which is not supposed to be.
Description Amount
Proc 1 100
Proc 2 50
Can you help me with this?
You could try below with sample data which you have provided
First, it will generated row numbers by using row_number() function partition by Description and Payment column which has duplicate payment made & sum() if have duplicate payments made
;WITH cte AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY [Description],
Payment ORDER BY [Description]) rn
FROM <TABLE 2>)
SELECT t.[Description],
CASE
WHEN COUNT(DISTINCT c.rn) > 1 THEN SUM(c.Payment)
ELSE MAX(t.amount) - SUM(c.Payment)
END [Balance]
FROM cte c
JOIN <TABLE 1> t ON t.[Description] = c.[Description]
GROUP BY t.[Description];
Result :
Description Balance
Proc 1 10
Proc 2 40
Proc 3 0
Note, But you could also check with your sample data what if one Description has both Payments made one is duplicate and other is unique ??
You're maths isn't correct
Proc 2 = Tabl1 50, Tab2 20+ 20 = balance = 10
DECLARE #tab1 TABLE ([Description] NVARCHAR(15), Qty INT, Amount INT )
INSERT INTO #tab1
([Description], Qty, Amount)
SELECT 'Proc 1',1,100 UNION ALL
SELECT 'Proc 2',1,50 UNION ALL
SELECT 'Proc 3',1,60
DECLARE #tab2 TABLE ([Description] NVARCHAR(15), Payment INT)
INSERT INTO #tab2
([Description], Payment)
SELECT 'Proc 1', 60 UNION ALL
SELECT 'Proc 1', 30 UNION ALL
SELECT 'Proc 2', 20 UNION ALL
SELECT 'Proc 3', 60 UNION ALL
SELECT 'Proc 2', 20
SELECT
T.[Description]
, Balance = (T.Qty * T.Amount) - X.Payment
FROM #tab1 T
INNER JOIN
(
SELECT
T.[Description]
, Payment = SUM(T.Payment)
FROM #tab2 T
GROUP BY T.[Description]
) X ON X.[Description] = T.[Description]
Left joining from a derived table will solve your issue. Alternatively you could have done it the slightly longer route by doing aggregation in a cte and then a join
select t1.description
,t1.amount - t2.sum as balance
from table1 t1
left join
(select description
,sum(payment) as sum
from table2
group by description) t2 on t1.description = t2.description
Just some food for thought:
You want to use a left join instead of an inner join. Left join says if it's in this first table and not second, show null. Inner join says show it only if it is in BOTH tables. And I'm guessing you want to show the balance even if a payment hasn't been made (just a guess but that's up to your report).
Here's the rextester sample you can play with.

Delete rows from table based on condition if other data exists within the table

I have the following data returned by a query:-
CUSTACCOUNT DIVISION EXTPERSON SALESMAN
C0001729 ECD 5637263283 Ian
C0001729 Fuel 5637369057 Peter
C0001729 Fuel NULL House
C0001729 ECD NULL House
C0001729 BSC 5637263239 Andrew
I would like a way to delete all rows which have null in the EXTPERSON column only if another row has the same DIVISION and EXTPERSON has a value, if they do not then to leave the rows in and not delete... I hope that makes sense. Is there a way to do this?
Is there a simple way of doing this?
Please use below code, assuming #ACCOUNTS has your table data
DELETE A FROM #ACCOUNTS A
WHERE EXTPERSON IS NULL
AND EXISTS (SELECT 1 FROM #ACCOUNTS B
WHERE A.DIVISION = B.DIVISION
AND ISNULL(B.EXTPERSON,0)<>0)
For such tasks, I used to left join and check in where if I have a link.
For exemple, for a SQL struct as:
`a`(`id`, `type`, `val`)
If i want to "select only lines, ID included, that already have the same type than another"...
select a1.* from `a` a1 left join `a` a2 on a2.`type`=a1.`type` and a2.`id`!=a1.`id` where a2.`id` is not null;
Such a task may also be performed with a subquery using group by, count, having... But subqueries are. Erm. Subqueries.
DELETE from TABLE1 T1 where EXISTS
(select CUSTACCOUNT, DIVISION, EXTPERSON,SALESMAN from TABLE2 T2
where EXTPERSON IS NULL AND T1.DIVISION<>T2.DIVISION
) and EXTPERSON IS NULL
Sample data setup:
create table #data (CUSTACCOUNT varchar(50), DIVISION varchar(50), EXTPERSON varchar(50), SALESMAN varchar(50))
insert into #data values
('C0001729', 'ECD', '5637263283', 'Ian'),
('C0001729', 'Fuel', '5637369057', 'Peter'),
('C0001729', 'Fuel', NULL, 'House'),
('C0001729', 'ECD', NULL, 'House'),
('C0001729', 'BSC', '5637263239', 'Andrew'),
('C0001729', 'SomeOther', NULL, 'Name')
Delete query:
;with aData
as (
select
rn = row_number() over (partition by DIVISION order by EXTPERSON desc),
cntExt = count(EXTPERSON) over (partition by DIVISION)
from #data
)
delete from aData
where rn > cntExt and cntExt > 0
Check table data:
select * from #data
Output:
CUSTACCOUNT DIVISION EXTPERSON SALESMAN
------------ ----------- ----------- ----------
C0001729 ECD 5637263283 Ian
C0001729 Fuel 5637369057 Peter
C0001729 BSC 5637263239 Andrew
C0001729 SomeOther NULL Name
you can use following query:
DELETE FROM t
FROM tbl t
WHERE
EXTPERSON IS NULL
AND EXISTS(
SELECT 1 FROM tbl WHERE t.DIVISION =DIVISION AND EXTPERSON IS NOT NULL
)
Explanation:
We are deleting the rows which are null and in the outer WHERE query part we check for other rows which have dame DIVISION but have value in EXTPERSON.
Test scripts:
create table tbl ( CUSTACCOUNT nvarchar(20),DIVISION nvarchar(20), EXTPERSON nvarchar(20),SALESMAN nvarchar(20))
INSERT INTO tbl values
('C0001729','ECD','5637263283','Ian')
,('C0001729','Fuel','5637369057','Peter')
,('C0001729','Fuel', NULL,'House')
,('C0001729','ECD', NULL,'House')
,('C0001729','BSC','5637263239','Andrew')
select * from tbl
begin transaction
DELETE FROM t
FROM tbl t
WHERE
EXTPERSON IS NULL
AND EXISTS(
SELECT 1 FROM tbl WHERE t.DIVISION =DIVISION AND EXTPERSON IS NOT NULL
)
select * from tbl
rollback transaction
drop table tbl
Result:
delete delTable
from table delTable
join table hasValue
on delTable.EXTPERSON is null
and hasValue.EXTPERSON is not null
and delTable.DIVISION = hasValue.DIVISION

Merge duplicate records and update its table

Can you help me with my problem with SQL Query?
I want to merge/(sum if necessary) all data of the customer with duplicate customer mame.
In my project, I already find out all the customer that has been duplicated using this code:
select Firstname, Lastname, count(1) as RepeatedCount
from customer
group by FirstName, LastName
having count(1) > 1
How can I update Customer table with only 1 customer record and get the sum of totalsales and totavisits in one record only.
Sample data:
FirstName LastName TotalSales TotalVisits
---------- ---------- -------------- -----------
Michelle Go 0.00 0
Michelle Go 6975.00 1
Michelle Go 1195.00 1
Michelle Go 9145.00 3
Michelle Go 57785.00 5
Michelle Go 5845.00 1
Michelle Go 0.00 0
Michelle Go 0.00 0
Expected Output:
FirstName LastName TotalSales TolalVisits
---------- ---------- -------------- -----------
Michelle Go 80945.00 11
You have use the aggregate function SUM with GROUP BY.
Query
SELECT FirstName,LastName,
SUM(totalsales) as totalsales,
SUM(totalvisits) as totalvisits
FROM customer
GROUP BY FirstName,LastName;
And for better practice I suggest you to add a column for customerId which is unique.
So that you can group it easily.
SQL Fiddle
You could use SUM and GROUP BY and insert the results in a temporary table.
IF OBJECT_ID('tempdb..#tempTable') IS NOT NULL
DROP TABLE #tempTable
SELECT
c.FirstName,
c.LastName,
SUM(c.TotalSales) AS TotalSales,
SUM(c.TotalVisits) AS TolalVisits
INTO #tempTable
FROM Customer c
GROUP BY c.LastName, c.FirstName
The, TRUNCATE the original table, Customer, and INSERT the data of #tempTable:
TRUNCATE TABLE Customer
INSERT INTO Customer
SELECT * FROM #tempTable
Let us consider below CTE as main table.
;WITH user_details
AS
(
SELECT 'Michelle' AS FirstName,'Go' AS LastName,0.00 AS totalsales,0 AS totalvists
UNION
SELECT 'MICHELLE','GO',6975.00,1
UNION
SELECT 'michelle','go',1195.00,1
UNION
SELECT 'michelle','go',9145.00,3
UNION
SELECT 'MICHELLE','GO',57785.00,5
UNION
SELECT 'MICHELLE','GO',5845.00,1
UNION
SELECT 'Michelle','Go',0.00,0
UNION
SELECT 'Michelle','Go',0.00,0
)
Group your query with aggregate function and insert into a temp table
SELECT
FirstName,
LastName,
SUM(totalsales) [totalsales],
SUM([totalvists]) [totalvisits]
INTO
#temp
FROM
user_details
GROUP BY
FirstName,
LastName
-- select * from #temp
Truncate your Main table
TRUNCATE TABLE user_details
Now again insert the updated records into your new table
INSERT INTO user_details (FirstName,LastName,totalsales,totalvisits -- Main table
SELECT
FirstName,
LastName,
totalsales,
totalvisits
FROM
#temp

SQL joined table pivot without aggregate

I have two tables:
Table1
ID TYPE
1 ABC1
2 ABC2
3 ABC3
Table2
ID Data
1 100
1 101
2 10
2 90
And I want the results to look like this:
ID Data1 Data2
1 100 101
2 10 90
But I'm having a total mare with my attempts at creating the pivot. So far I have:
With Inital_Data As (
Select
A.ID,
B.Data As Data1,
B.Data As Data2
From
Table1 A join
Table2 B on
A.ID = B.ID
)
Select *
From
Initial_Data
PIVOT
(Max(ID) FOR Data IN (Data1,Data2)) p
I know this is rubbish but so far even the logic of what I'm trying to achieve is escaping me, let alone the syntax! Can anyone give me a guiding hand?
Pivot with more than one column needs some tricks, I prefer the XML concatenation. First I take all values for each ID in only one XML, then you can take these values one by one:
Just paste this into an empty query window and execute. Adapt for your needs
EDIT: Includes column Type from TABLE1 as Caption for ID...
DECLARE #Table1 TABLE(ID INT,[TYPE] VARCHAR(10));
INSERT INTO #Table1 VALUES
(1,'ABC1')
,(2,'ABC2')
,(3,'ABC3');
DECLARE #Table2 TABLE(ID INT,DATA INT);
INSERT INTO #Table2 VALUES
(1,100)
,(1,101)
,(2,10)
,(2,90);
WITH DistinctIDs AS
(
SELECT DISTINCT tbl2.ID,tbl1.[TYPE]
FROM #Table2 AS tbl2
INNER JOIN #Table1 AS tbl1 ON tbl1.ID=tbl2.ID
)
SELECT ID,[TYPE]
,concatXML.x.value('/root[1]/item[1]/#data','int') AS Data1
,concatXML.x.value('/root[1]/item[2]/#data','int') AS Data2
FROM DistinctIDs AS dIDs
CROSS APPLY
(
SELECT ID AS [#id],DATA AS [#data]
FROM #Table2 AS tbl WHERE tbl.ID=dIDs.ID
FOR XML PATH('item'), ROOT('root'),TYPE
) AS concatXML(x)

Sql server union but keep order

Is there a way to union two tables, but keep the rows from the first table appearing first in the result set?
For example:
Table1
name surname
-------------------
John Doe
Bob Marley
Ras Tafari
Table2
name surname
------------------
Lucky Dube
Abby Arnold
I want the result set to look like:
name surname
-------------------
John Doe
Bob Marley
Ras Tafari
Lucky Dube
Abby Arnold
Unfortunately, union somehow reorders the table. Is there a way around this?
Try this :-
Select *
from
(
Select name,surname, 1 as filter
from Table1
Union all
Select name,surname , 2 as filter
from Table2
)
order by filter
The only way to guarantee output order is to use ORDER BY:
SELECT name,surname,1 as rs
FROM table1
UNION ALL
SELECT name,surname,2
FROM table2
ORDER BY rs
If you don't want rs to appear in the final result set, do the UNION as a subquery:
SELECT name,surname
FROM (
SELECT name,surname,1 as rs
FROM table1
UNION ALL
SELECT name,surname,2
FROM table2
) t
ORDER BY rs
;WITH cte as (
SELECT name, surname, 1 as n FROM table1
UNION ALL
SELECT name, surname, 2 as n FROM table2
UNION ALL
SELECT name, surname, 3 as n FROM table3
)
SELECT name, surname
FROM cte
ORDER BY n;
.Like this?
CREATE TABLE #Table1 (Names VARCHAR(50))
CREATE TABLE #Table2 (Names VARCHAR(50))
INSERT INTO #Table1
(
Names
)
VALUES
('John Doe'), ('Bob Marley'), ('Ras Tafari')
INSERT INTO #Table2
(
Names
)
VALUES
('Lucky Dube'), ('Abby Arnold')
SELECT ArbSeq = 1, *
FROM #Table1
UNION ALL
SELECT ArbSeq = 2, *
FROM #Table2
ORDER BY ArbSeq
It should be noted that ordering is not guaranteed when not explicitly defined.
If the table features a clustered index, the rows will typically be returned in the index's order - but this is not guaranteed.

Resources