Join get wrong information on query - sql

I'm having some problems with join query. What I want is select rows of two tables that have some similar states, others no. And I have a state-equivalence view
Table Sales:
ID ..... StateID
1 1
2 1
3 6
Table Orders
ID ..... StateID
11 2
12 2
15 3
Table StatesEquivalence
ID SalesState OrdersState StateName
1 1 2 Attended
2 2 3 Declined
I've made a union of both tables(Sales and Orders) and I want a column with the EquivalentStateID and the StateName by doing something like this:
SELECT sales.ID as ID,equivalence.ID as State,equivalence.StateName
FROM Sales
INNER JOIN StatesEquivalence as equivalence
ON sales.StateID = equivalence.SalesState
WHERE sales.ID = 1
UNION
SELECT orders.ID as ID,equivalence.ID as State,equivalence.StateName
FROM Orders as orders
INNER JOIN StatesEquivalence as equivalence
ON orders.StateID = equivalence.OrdersState
Somehow I am obtaining wrong information on the equivalentID
ID State StateName
1 2 Attended
2 2 Attended
11 2 Attended
...
I don't know what happend.. because the statename is correct, but the StateID is showing wrong information
The table might show this:
ID State StateName
1 1 Attended
2 1 Attended
11 1 Attended
...

I don't think you are showing us the real problem code. I did the following:
begin transaction
create table sales (id int, stateid int)
create table orders (id int, stateid int)
create table statesequivalence (id int, salesstate int, ordersstate int, statename varchar(20))
insert into sales values (1, 1)
insert into sales values (2, 1)
insert into sales values (3, 6)
insert into orders values (11, 2)
insert into orders values (12, 2)
insert into orders values (15, 3)
insert into statesequivalence values (1, 1, 2, 'Attended')
insert into statesequivalence values (2, 2, 3, 'Declined')
SELECT sales.ID as ID,equivalence.ID as State,equivalence.statename
FROM Sales
INNER JOIN statesequivalence as equivalence
ON sales.StateID = equivalence.SalesState
WHERE sales.ID = 1
UNION
SELECT orders.ID as ID,equivalence.ID as State,equivalence.StateName
FROM Orders as orders
INNER JOIN statesequivalence as equivalence
ON orders.StateID = equivalence.OrdersState
rollback
Result:
ID State statename
----------- ----------- --------------------
1 1 Attended
11 1 Attended
12 1 Attended
15 2 Declined
So, it works. Can you try the above code?

Following is a testscript and the output from your statement.
Perhaps it's easier to work from here and you tell us what is wrong with this output.
The testscript can be adjusted and executed here
Output
ID State StateName
----------- ----------- ---------
1 1 Attended
11 1 Attended
12 1 Attended
15 2 Declined
Test Script
;WITH Sales AS (
SELECT * FROM (VALUES
(1, 1)
, (2, 1)
, (3, 6)
) AS Sales (ID, StateID)
)
, Orders AS (
SELECT * FROM (VALUES
(11, 2)
, (12, 2)
, (15, 3)
) AS Orders (ID, StateID)
)
, StatesEquivalence AS (
SELECT * FROM (VALUES
(1, 1, 2, 'Attended')
, (2, 2, 3, 'Declined')
) AS StatesEquivalence (ID, SalesState, OrdersState, StateName)
)
SELECT sales.ID as ID
, equivalence.ID as State
, equivalence.StateName
FROM Sales
INNER JOIN StatesEquivalence as equivalence ON sales.StateID = equivalence.SalesState
WHERE sales.ID = 1
UNION
SELECT orders.ID as ID
, equivalence.ID as State
, equivalence.StateName
FROM Orders as orders
INNER JOIN StatesEquivalence as equivalence ON orders.StateID = equivalence.OrdersState

I didn't understand what you need exactly, but maybe is this?
select *
from StatesEquivalence EQ
full join Sales S on EQ.SalesState = S.StateId
full join Orders O on EQ.OrdersState = O.StateId
This is a starting point maybe...

Related

Combine Data from Multiple tables SQL server

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;

Get SQL Server result using subquery

I have a Members table like this:
PersonID FirstName Address City date
---------------------------------------------------------
3 Rasanga Skagen 21 South 2019-01-05
and a Persons table:
PersonID FirstName Address City date
-------------------------------------------------------
3 Rasanga Skagen 21 South 2019-01-06
1 Tom B. Skagen 21 Colombo 2018-01-07
2 Tom B. Skagen 21 Colombo 2019-01-05
I want to get Persons that do not exists in Members table using the FirstName column. For that I'm using this query:
SELECT *
FROM Persons p
WHERE NOT EXISTS (SELECT * FROM Members m WHERE m.FirstName = p.FirstName)
When I execute above query I'm getting same FirstName and 2 records but my requirement is if there's 2 records for same name retrieve latest record using date column. Therefore above scenario it should be Tom B. with 2018-01-07 record. If both records have same date should retrieve 1 record from 2 records.
Can somebody explain how to do this?
You can use the left join and checking the Members.PersonId is null.
create table Members(PersonID int
, FirstName varchar(20)
, Address varchar(50)
, City varchar(50)
, Dtdate date)
insert into Members values
(3, 'Rasanga', 'Skagen 21', 'South', '2019-01-05')
Create table Persons(PersonID int
, FirstName varchar(20)
, Address varchar(50)
, City varchar(50)
, Dtdate date)
insert into Persons values
(3, 'Rasanga', 'Skagen 21', 'South', '2019-01-06'),
(1, 'Tom B.', 'Skagen 21', 'Colombo', '2018-01-07'),
(2, 'Tom B.', 'Skagen 21', 'Colombo', '2019-01-05')
Select Persons.* from Persons
left join Members on Persons.PersonID = Members.PersonID
where Members.PersonId is null
Demo
Using the not exists you can check as shown below.
SELECT Persons.*
FROM Persons
WHERE NOT EXISTS (SELECT 1
FROM Members
WHERE Persons.PersonID = Members.PersonID)
Using the in operator
SELECT * FROM Persons
WHERE PersonID NOT IN (
SELECT PersonID FROM Members
)
To get the unique records based on the first name and date you can use the following query using ROW_NUMBER() function.
;WITH cte
AS (
SELECT Persons.*
,ROW_NUMBER() OVER (
PARTITION BY Persons.FirstName ORDER BY Persons.Dtdate DESC
) AS RN
FROM Persons
LEFT JOIN Members ON Persons.PersonID = Members.PersonID
WHERE Members.PersonId IS NULL )
SELECT *
FROM CTE
WHERE RN = 1
Output
PersonID FirstName Address City Dtdate RN
----------------------------------------------------------
2 Tom B. Skagen 21 Colombo 2019-01-05 1
You could use a window function as
SELECT T.PersonID,
T.FirstName,
T.Address,
T.City,
T.[Date]
FROM
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY FirstName ORDER BY [Date] DESC) RN
FROM Persons
) T
WHERE NOT EXISTS
(
SELECT 1
FROM Members
WHERE FirstName = T.FirstName
) AND T.RN = 1;
Here is a db<>fiddle

SQL Query Parent Child

Can you help me?
Table: LOS
ID Name ParentID
1 Item Null
2 Pharmacy 1
3 Consumable 1
4 Ethical 2
5 Non Ethical 2
6 MCCP 4
7 Nurse 3
Table: Item
id ItemName lOS_Id Los_Name
123 Panadol 6 MCCP
321 Nacl 7 Nurse
Expected Result.
ID ItemName ParentID ParentName LOS_Id Los_Name
123 Panadol 2 Pharmacy 6 MCCP
321 Nacl 3 Consumable 7 Nurse
Explanation : ParentID from los_id join LOS Table using ID THEN Get parentID to find Parent
Just see this example.
Declare #LOS table (ID int, Name nvarchar(50), ParentID int)
Declare #Item table (ID int, ItemName nvarchar(50), lOS_ID int, lOS_Name nvarchar(50) )
Insert into #LOS values (1, 'Item',null), (2 ,'Pharmacy', 1), (3 ,'Consumable', 1), (4 ,'Ethical', 2), (5 ,'Non Ethical', 2), (6 ,'MCCP', 4)
, (7 ,'Nurse', 3)
Insert into #Item values (123, 'Panadol',6 ,'MCCP'), (321, 'Nacl',7 ,'Nurse')
select * from #LOS
select * from #Item
;with cte as
(
select i.id, ItemName, lOS_ID, lOS_Name, lOS_ID parentid, lOS_ID parentparentid, lOS_Name parentname from #Item i
join #los l on i.lOS_ID = l.id
-- where i.id = 123
union all
select
c.id, ItemName, lOS_ID, lOS_Name, l.ID parentid, l.ParentID parentparentid, l.Name parentname
from
cte c join #los l on c.parentparentid = l.id --and c.ParentID <> null
)
select * from cte where parentparentid = 1
order by id
I hope I understood you correctly and this query will fix your problem :)
select I.ID, I.ItemName, A.ParentID, A.ParentName, I.LOS_ID, I.LOS_Name from Item AS I join (
select l1.id, l1.name, l1.ParentID, l2.name as ParentName from LOS as l1 join LOS as l2 on l1.id = l2.ParentID
) as A join on I.LOS_ID = A.ID

How to do Sum Operation in SQl Pivot Query

Here i have a simple table Name Cust With CustName,PurshaseItem,Price.I wrote a Simple PIVOT query its Pivoting the data but i wana to show sum of the amot
Here i need Grand total
Pivot Query
[![select custName,
\[Shoes\] as Shoes,
\[Colgate\] as Colgate,
\[Cloths\] as Cloths
FROM
(select custName,Price,PurchaseItem FROM Cust
) AS PIVOTData
PIVOT(
sum(Price) FOR PurchaseItem
IN (Shoes,Colgate,Cloths)
)AS PIVOTING][1]][1]
custname Shoes Colgate GrandTotal
xyz 12 10 22
lmn 1 2 3
You can try this:
CREATE TABLE CUST (custName VARCHAR(10),
price INT,
PurchaseItem VARCHAR(10)
)
INSERT INTO CUST VALUES ('aaaa', 1,'Colgate')
INSERT INTO CUST VALUES ('aaaa', 2,'Shoes')
INSERT INTO CUST VALUES ('aaaa', 3,'Cloths')
INSERT INTO CUST VALUES ('bbbb', 4,'Colgate')
INSERT INTO CUST VALUES ('bbbb', 5,'Shoes')
INSERT INTO CUST VALUES ('bbbb', 6,'Cloths')
select *
FROM
(select custName, SUM(Price) AS Price ,
CASE WHEN GROUPING(PurchaseItem)=1 THEN 'TOT_PRICE' ELSE PurchaseItem END AS PurchaseItem
FROM Cust
group by rollup(PurchaseItem), custName
) AS PIVOTData
PIVOT(sum(Price) FOR PurchaseItem IN (Shoes,Colgate,Cloths,TOT_PRICE)) AS PIVOTING
Output:
custName Shoes Colgate Cloths TOT_PRICE
---------- ----------- ----------- ----------- -----------
aaaa 2 1 3 6
bbbb 5 4 6 15
You can just add this to your select
coalesce([Shoes], 0) + coalesce([Colgate], 0) + coalesce([Cloths], 0) as GranTotal
The coalesce is needed to avoid weird behaviours when one of the results is null.

SQL: How to find the sum of values where all the records has the same value in a column?

I have Payments table with multiple columns, including Student, Value and Payment_type.
I want to create a query that will calculate the sum of values, if all the records of the same student have only NULL as Payment type.
If a student has at least one Payment type different than NULL, that student shouldn't be included.
Example:
Student Payment Value Payment_type
1 1 100 NULL
1 2 200 NULL
2 1 200 NULL
3 1 150 Cash
2 2 100 Cash
3 2 200 NULL
1 3 200 NULL
If you look at the example, it should give me result 500, because the sum of values of student 1 is 500, and his/her ALL payment types are NULL.
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Payments
(`Student` int, `Payment` int, `Value` int, `Payment_type` varchar(4))
;
INSERT INTO Payments
(`Student`, `Payment`, `Value`, `Payment_type`)
VALUES
(1, 1, 100, NULL),
(1, 2, 200, NULL),
(2, 1, 200, NULL),
(3, 1, 150, 'Cash'),
(2, 2, 100, 'Cash'),
(3, 2, 200, NULL),
(1, 3, 200, NULL)
;
Query 1:
select student, sum(value)
from payments
group by student
having max(Payment_type) IS NULL
Results:
| Student | sum(value) |
|---------|------------|
| 1 | 500 |
select student, sum(value)
from payments
group by student
having sum(case when Payment_type is not null then 1 else 0 end) = 0
This should work:
select
student, sum(value)
from
payments
group by
student
having sum
(case when Payment_type is not null then 1 else 0 end) = 0
For me, this is very clean, plus semantically accurate regarding your description:
SELECT student, SUM(value)
FROM payments p1
WHERE NOT EXISTS (SELECT 1
FROM payments p2
WHERE p2.student = p1.student
AND Payment_type IS NOT NULL)
GROUP BY student