Combine Data from Multiple tables SQL server - sql

Hello I have 3 Tables in Database Customer, Payment and Refund. Structure is as below:
Customer Table:
CustId
Notes
1
hi
2
hello
3
gg
4
hh
Payment Table:
pmtId
custId
PmtNotes
10
1
kk
11
2
pp
12
3
NULL
15
4
dd
Refund Table:
refId
custId
refNotes
33
1
ww
34
2
mm
35
3
jj
65
2
ii
Expected Result:
CustId
Notes
col1
3
gg
1
3
JJ
3
col1 = 1: Because this data is from Customer table.
col1 = 3: Because this data is from Refund table.
I want this type of result based on the customer id, I found similar questions but I can't find the most relevant solution for this.
Any help would be appreciated as I am quite a beginner in SQL server.

If I understood you correctly you want to select customer with notes from different tables along with the indication of which table the data belongs to. I have considered rows only with non null notes. Please check.
First I have union all rows from three tables where notes column is not null and added an extra column to indicate table from which that row has come.
Schema and insert statements:
create table Customer (CustId int, Notes varchar(50));
insert into Customer
values
(1 , 'hi' ),
(2 , 'hello' ),
(3 , 'gg' ),
(4 , 'hh' );
create table Payment (pmtId int, custId int ,PmtNotes varchar(50));
insert into Payment values
(10 ,1 , 'kk'),
(11 ,2 , 'pp'),
(12 ,3 , NULL),
(15 ,4 , 'dd');
create table Refund (refId int, custId int, refNotes varchar(50));
insert into Refund values
(33 ,1 , 'ww'),
(34 ,2 , 'mm'),
(35 ,3 , 'jj'),
(65 ,2 , 'ii');
Query:
select * from
(
select custid, notes, 1 Col1 from customer where notes is not null
union all
select custid, PmtNotes, 2 Col1 from Payment where PmtNotes is not null
union all
select custid, refNotes, 3 Col1 from Refund where refNotes is not null
)t where custid=3
Output:
custid
notes
Col1
3
gg
1
3
jj
3
db<fiddle here

This should work.
SELECT * FROM Customer
LEFT JOIN payment
ON customer.CustId = Payment.custId
LEFT JOIN Refund
ON customer.CustId = Refund.CustId
OR
SELECT * FROM Customer
LEFT JOIN payment
ON customer.CustId = Payment.custId
LEFT JOIN Refund
ON customer.CustId = Refund.CustId
WHERE Customer.CustId = 2
Add the WHERE Clause to filter to a single customer or remove all entries. A Left Join will bring empty cols too.

This seems to be what you are after; just a couple of JOINs and an unpivot:
SELECT C.CustID,
V.Notes,
V.Col1
FROM dbo.Customer C
JOIN dbo.Payment P ON C.CustID = P.CustID --Might need to be a LEFT JOIN
JOIN dbo.Refund R ON C.CustID = R.CustID --Might need to be a LEFT JOIN
CROSS APPLY(VALUES(C.Notes,1),
(P.PmtNotes,2),
(R.RefNotes,3))V(Notes,Col1)
WHERE C.CustID = 3
AND V.Notes IS NOT NULL;

Related

How can I prevent cartesian product to avoid double counting

I am getting wrong data (cartesian product) when using inner join.
Table t1
PurchaseOrder CostID Amount
1 1 4
1 2 3
Table t2
PurchaseOrder OrderType ItemId
1 321 1
1 321 2
1 321 3
1 321 4
2 128 5
2 128 6
3 321 9
Required Output
PurchaseOrder Amount
1 7
My Output
PurchaseOrder Amount
1 28
I am trying to use inner join to get the output but not getting the right data.
Query:
CREATE TEMP TABLE t1
(
PurchaseOrder INT64,
CostID INT64,
Amount INT64
);
INSERT INTO t1
VALUES (1,1,4),(1,2,3);
SELECT *
FROM t1;
CREATE TEMP TABLE t2
(
PurchaseOrder INT64,
OrderType INT64
);
INSERT INTO t2
VALUES (1,321),(1,321),(1,321),(1,321);
SELECT *
FROM t2;
select t1.PurchaseOrder, sum(amount)
from t1 inner join t2 on t1.PurchaseOrder = t2.PurchaseOrder
where t2.OrderType = 321
group by t1.PurchaseOrder;
I think you just want to check if some PurchaseOrder has an OrderType 321, that is what you use Table 2 for, to do this check. But then to sum the amounts, all information is already in Table 1. So I would write the query as follows:
select PurchaseOrder, sum(amount)
from t1
where exists
(select * from t2
where PurchaseOrder=t1.PurchaseOrder
and OrderType=321)
group by PurchaseOrder

SQL query with conditions for audit

I want to write a SQL query for several columns with conditions. the table looks like this:
ID Company User
1 Bov LPF
2 Ak LPF
3 Bov LPF
4 Bov ABC
5 Ak ABC
6 ZP ABC
7 REP ABC
8 REP CDE
9 KEK CDE
10 Ak CDE
11 PER CDE
12 Bov BKE
The result must be as followed:
Give me three rows per user (only the users with at least three rows will be in the result).
Company Bov, REP and Ak must return at least two times in the result
It is for an audit so everything must be ordered randomly (order by newid() for example)
Total rows is 9.
Expected result for example:
ID Company User
1 Bov LPF
2 Ak LPF
3 Bov LPF
4 Bov ABC
5 Ak ABC
7 REP ABC
8 REP CDE
10 Ak CDE
11 PER CDE
How should i write the query?
Update:
I was thinking about a query like this, but this doesn't give me the right results:
select *
from
(
select *,row_number() over(partition by user,company order by user, company) as row, ROW_NUMBER() over(order by newid()) as total
from
(
select *
from
(
select *, 0 as Bov, sum(iif(Company= 'Ak',1,0)) over (order by newid()) as Ak
FROM table a
where Company = 'Ak'
) as eu
where eu.Ak <= 2
UNION ALL
select *
from
(
select *, sum(iif(company = 'Bov',1,0)) over (order by newid() ) as Bov, 0 as Ak
FROM table a
where Company = 'Bov'
) as nn
where nn.Bov <= 2
UNION ALL
select *, 0 as Bov, 0 as Ak
FROM table a
where Company not in ('Bov','Ak')
) as z
) as z1
where z1.row <= 3
and z1.total <= 9
Filter <= 2 is for the company that must return at least two times in the result
Filter row <= 3 is for the three rows per user.
Filter total <= 9 is for the total rows that must be 9.
With this query i am not for sure that i have at least two rows for the companies Bov, Ak and REP.
select *
from table
group by id
having count(User) <= 3
order by id
Is this what you need?
You can use this.
DECLARE #MyTable TABLE (ID INT, Company VARCHAR(10), [User] VARCHAR(10))
INSERT INTO #MyTable VALUES
(1 , 'Bov', 'LPF'),
(2 , 'Ak ', 'LPF'),
(3 , 'Bov', 'LPF'),
(4 , 'Bov', 'ABC'),
(5 , 'Ak ', 'ABC'),
(6 , 'ZP ', 'ABC'),
(7 , 'REP', 'ABC'),
(8 , 'REP', 'CDE'),
(9 , 'KEK', 'CDE'),
(10 , 'Ak ', 'CDE'),
(11 , 'PER', 'CDE'),
(12 , 'Bov', 'BKE')
SELECT ID, Company, [User] FROM
( SELECT *
, ROW_NUMBER() OVER (PARTITION BY [User] ORDER BY (CASE WHEN Company IN ('Bov','REP','Ak') THEN 0 ELSE 1 END) ) RN
, COUNT(*) OVER (PARTITION BY [User]) CmpCnt
, COUNT(CASE WHEN Company IN ('Bov','REP','Ak') THEN 1 END) OVER (PARTITION BY [User]) PriCmpCnt
FROM #MyTable
) T
WHERE
T.CmpCnt > 2
and T.PriCmpCnt > 1
and T.RN < 4
order by ID
Result:
ID Company User
----------- ---------- ----------
1 Bov LPF
2 Ak LPF
3 Bov LPF
4 Bov ABC
5 Ak ABC
7 REP ABC
8 REP CDE
10 Ak CDE
11 PER CDE
Here's how I'd approach it; see comments for explanation / let me know if you need anymore info to understand anything...
SQL Fiddle Demo
;with cte as
(
select Id
, Company
, [User]
, Row_Number() over (partition by [User] order by randomOrder) PerUserRowNum
, case
when Company in ('BOV','REP', 'AK') then
case
when Row_Number() over (partition by Company order by randomOrder) <= 2 then 1
else 0
end
else 0
end MustInclude
from (select *, newid() randomOrder from SourceData) x
)
select top 9 --total rows is 9
Id, Company, [User]
from cte
where PerUserRowNum <= 3 --show 3 rows per user
and [User] in ( --only the users with at least three rows will be in the result
select [User]
from cte
where PerUserRowNum = 3
)
order by MustInclude desc, newid() --ensure all the stuff we must include is returned, then make up the rest of the results with whatever

SQL query Group by while using Union All

I am completely New to SQL queries and need help in combining some select statements together to form one single query.
I will start one query at a time:
select sum(DOCI)
from (
select POL.SP_NUM, sum(Q.AMT + POL.AMT) DOCI
from S_ASSET POL
, S_QUOTE_ITEM Q
where POL.X_QUOTE_ID = Q.ROW_ID
and POL.SP_NUM in ('000','111','222')
group by POL.SP_NUM
UNION ALL
select POL.SP_NUM, sum(QXM.AMT) DOCI
from S_ASSET POL
, S_QUOTE_ITEM Q
, S_QUOTE_ITEM_XM QXM
where POL.X_QUOTE_ID = Q.ROW_ID
and Q.ROW_ID = QXM.PAR_ROW_ID
and POL.SP_NUM in ('000','111','222')
group by POL.SP_NUM
)
Tables:
S_ASSET
X_QUOTE_ID POL AMT
A 000 1
B 111 1
C 222 1
S_QUOTE_ITEM
ROW_ID AMT
A 10
B 10
C 1
S_QUOTE_ITEM_XM
PAR_ROW_ID AMT
A 10
B 0
Expected O/P:
POL AMT(sum)
A 21
B 11
C 2
Please help
SELECT sp_num, SUM(doci)
FROM ( ...subquery... )
GROUP BY sp_num;
The table name pol only exists inside the subquery. The outer query is selecting from the result of the subquery, not from any named table.

Recursive query in DB2 to get all items in the chain

I have to retrieve all clients linked via loans by giving only one as input. Example I have a table data as
TABLEA
LOAN_ID CLIENT_ID
1 7
1 8
2 7
4 8
4 9
4 10
5 9
5 11
13 2
14 3
If I have given only input as CLIENT_ID=7 then the query has to select all the columns from above table except last two column because client_id 7 has 1,2 LOAN_ID and in 1 the CLIENT_ID 8 has loan_id=4 and in this loan CLIENT_id 9 has again 5 as loan_id.
can we write a sql query for this without stored procedure in DB2 ?
Here is the answer to your question using recursive CTE query:
WITH links AS
( SELECT
loan_id,
client_id as c1,
client_id as c2, 0 as distance
FROM
myTable
-- recursion
UNION ALL
SELECT
t.loan_id,
l.c1 as c1,
tt.client_id as c2,
distance = distance + 1
FROM
links l INNER JOIN
myTable t ON l.c2 = t.client_id
AND l.loan_id != t.loan_id INNER JOIN
myTable tt ON t.loan_id = tt.loan_id
AND t.client_id != tt.client_id
)
SELECT * FROM myTable t
WHERE EXISTS
(SELECT * FROM links
WHERE c2 = t.client_id and c1 = 7);
http://sqlfiddle.com/#!3/8394d/16
I have left distance inside the query to make it easier to understand.

sql query to get data group by customer type and need to add default value if customer type not found

I have a table "Customers" with columns CustomerID, MainCountry and CustomerTypeID.
I have 5 customer types 1,2,3,4,5 .
I want to count number of customers of each country according to customer type. I am using the following query:
select count(CustomerID) as CustomerCount,MainCountry,CustomerTypeID
from Customers
group by CustomerTypeID,MainCountry
But some countries not have any customers, under type 1,2,3,4 or 5.
So I want to put a default value 0 for if customer type is not exist for that country.
Currently it is giving data as follows :-
CustomerCount MainCountry CustomerTypeID
5695 AU 1
525 AU 2
12268 AU 3
169 AU 5
18658 CA 1
1039 CA 2
24496 CA 3
2259 CA 5
2669 CO 1
10 CO 2
463 CO 3
22 CO 4
39 CO 5
As "AU" not have type 4 so I want a default value for it.
You should JOIN your table with a table with TypeId's. In this case
select count(CustomerID) as CustomerCount,TypeTable.MainCountry,TypeTable.TId
from
Customers
RIGHT JOIN (
select MainCountry,TId from
(
select Distinct MainCountry from Customers
) as T1,
(
select 1 as Tid
union all
select 2 as Tid
union all
select 3 as Tid
union all
select 4 as Tid
union all
select 5 as Tid
) as T2
) as TypeTable on Customers.CustomerTypeID=TypeTable.TId
and Customers.MainCountry=TypeTable.MainCountry
group by TypeTable.TId,TypeTable.MainCountry
Select Country.MainCountry, CustomerType.CustomerTypeId, Count(T.CustomerID) As CustomerCount
From (Select Distinct MainCountry From Customers) As Country
Cross Join (Select Distinct CustomerTypeId From Customers) As CustomerType
Left Join Customers T
On Country.MainCountry = T.MainCountry
And CustomerType.CustomerTypeId = T.CustomerTypeId
-- Edit here
And T.CreatedDate > Convert(DateTime, '1/1/2013')
-- End Edit
Group By Country.MainCountry, CustomerType.CustomerTypeId
Order By MainCountry, CustomerTypeId
Try that:
with cuntry as (
Select Distinct MainCountry From Customers
),
CustomerType as (
(Select Distinct CustomerTypeId From Customers
),
map as (
select MainCountry, CustomerTypeId from cuntry,CustomerType
)
select count(CustomerID) as CustomerCount,a.MainCountry,a.CustomerTypeID
from
map a left join Customers b on a.CustomerCount=b.CustomerCount and a.CustomerTypeID=b.CustomerTypeID