SELECT DISTINCT showing duplicate dates per customer email - sql-server

I am trying to retrieve information for the past ten months, but am having a couple of errors. First, my query is getting data from as far back as 2013. Secondly, I am seeing duplicates in my results based on the PolEffDate field, like this:
EntityID | PolEffDate | EMail | CustNo | Producer | BusinessPhone
abcde-12345-fghij-67890 | 2013-09-24 | somewhere#email.com | 31000 | Bob Builder | 123-456-7890
abcde-12345-fghij-67890 | 2013-12-01 | somewhere#email.com | 31000 | Bob Builder | 123-456-7890
abcde-12345-fghij-67890 | 2014-09-24 | somewhere#email.com | 31000 | Bob Builder | 123-456-7890
Here is my SQL Query:
SELECT DISTINCT
CONVERT(VarChar(36), Customer.CustId) AS EntityID
, BasicPolInfo.PolEffDate, Customer.EMail, Customer.CustNo
, (isnull(Employee.Firstname + ' ','') + isnull(Employee.LastName,''))
AS Producer, Employee.BusFullPhone
FROM
Customer INNER JOIN BasicPolInfo ON Customer.CustId = BasicPolInfo.CustId INNER JOIN
Transaction ON BasicPolInfo.PolId = Transaction.PolId INNER JOIN
GeneralBranch ON Customer.GLBrnchCode = GeneralBranch.GLBrnchCode INNER JOIN
GeneralDepartment ON Customer.GLDeptCode = GeneralDepartment.GLDeptCode INNER JOIN
GeneralDivision ON Customer.GLDivCode = GeneralDivision.GLDivCode INNER JOIN
Employee ON BasicPolInfo.ExecCode = Employee.EmpCode
WHERE
BasicPolInfo.PolExpDate >= DATEADD(MONTH, -10,CONVERT(VARCHAR(11),GETDATE(),106))
AND BasicPolInfo.PolExpDate <= CONVERT(VARCHAR(11),GETDATE(),106)
AND Customer.Active = 'Y'
AND Customer.typeCust = 'P'
Thank you for the help. I will try my best to answer any questions.

Daniel, the duplication you are seeing is caused because you have multiple records in BasicPolInfo for each CustID value. You can confirm this by running the following query:
SELECT CustID, COUNT(*)
FROM BasicPolInfo
GROUP BY CustID
HAVING COUNT(*) > 1
Depending on your schema, this may not be an issue - after all, there is probably a perfectly legitimate reason for that! Multiple policies per Customer is my guess.
To resolve the duplication, I would recommend a GROUP BY with MIN() or MAX().
Your other issue, that of retrieving data from earlier dates, is because you are selecting the PolEffDate (presumably, policy effective date), but filtering the PolExpDate (presumably, policy expiration date). Which are you intending to use? Policies that have finished sometime in the last ten months could have started much earlier than that.
To resolve the wider date range, reference the same value in your SELECT and WHERE clauses.
Query below (using MAX() and PolExpDate):
SELECT
CONVERT(VarChar(36), Customer.CustId) AS EntityID,
MAX(BasicPolInfo.PolExpDate) AS PolExpDate, -- note that this is now PolExpDate
Customer.EMail,
Customer.CustNo,
(isnull(Employee.Firstname + ' ','') + isnull(Employee.LastName,'')) AS Producer,
Employee.BusFullPhone
FROM
Customer INNER JOIN
BasicPolInfo ON Customer.CustId = BasicPolInfo.CustId INNER JOIN
[Transaction] ON BasicPolInfo.PolId = [Transaction].PolId INNER JOIN
GeneralBranch ON Customer.GLBrnchCode = GeneralBranch.GLBrnchCode INNER JOIN
GeneralDepartment ON Customer.GLDeptCode = GeneralDepartment.GLDeptCode INNER JOIN
GeneralDivision ON Customer.GLDivCode = GeneralDivision.GLDivCode INNER JOIN
Employee ON BasicPolInfo.ExecCode = Employee.EmpCode
WHERE
BasicPolInfo.PolExpDate >= DATEADD(MONTH, -10,CONVERT(VARCHAR(11),GETDATE(),106))
AND BasicPolInfo.PolExpDate <= CONVERT(VARCHAR(11),GETDATE(),106)
AND Customer.Active = 'Y'
AND Customer.typeCust = 'P'
GROUP BY
CONVERT(VarChar(36), Customer.CustId),
Customer.EMail,
Customer.CustNo,
(isnull(Employee.Firstname + ' ','') + isnull(Employee.LastName,'')),
Employee.BusFullPhone

Related

Why is my total not coming up correctly, and how can I fix it?

I'm working on remaking an Access report in SSRS with data from a SQL Server.
In the report I have a matrix, and one of the values is SumOfPieces.
SumOfPieces is in my Query as sum(t1.pieces) as SumOfPieces.
Inside the table I get the correct row values by just using [SumOfPieces], but my total is not adding anything together. For example this is what I am getting:
Product | Facility | Shift/Line | Pieces
BFS | BRWP | A 1 | 65,000
BFS | MHWP | A 2 | 70,000
BFS | MHWP | B 2 | 80,000
________________________________________
Total | | | 70,000
For some reason it's giving me the middle value
The expression for the total is simply =Sum(fields!SumOfPieces.Value)
I tried different variations of something like this expression =Sum(avg(fields!SumPieces.Value,"Product1")
In Access this is accomplished with queries nested 4-5 deep.
For this field specifically it looks like
Original query t1 with t1.Pieces
Next query on t1 with t1.Pieces summed as t1.SumOfPieces
Next query joins t1 with others
The Access report just uses that SumOfPieces as the row value, and then a sum(SumOfPieces) for the total.
Sample of my Dataset Query:
SELECT
StaveHistorySummary.fk_Inspectors
,StaveHistorySummary.fk_InspectionSites
,StaveHistorySummary.fk_ProductionLines
,StaveHistorySummary.fk_ProductTypes
,StaveHistorySummary.DateMade
,StaveHistorySummary.[TimeStamp]
,StaveHistorySummary.StaveHistoryguid
,InspectionSites.SiteAbbr
,Inspectors.Name
,ProductTypes.Product
,ProductionLines.LineName
,CAST(sum(Millproduction.Pieces) as int) AS SumPieces
,CASE
WHEN SapEdgingInches IS NOT NULL THEN SapEdgingInches
WHEN HeartEdgingInches IS NOT NULL THEN HeartEdgingInches
WHEN BothEdgingInches IS NOT NULL THEN BothEdgingInches
WHEN SawnIncorrInches IS NOT NULL THEN SawnIncorrInches
WHEN EqualizedIncorrInches IS NOT NULL THEN EqualizedIncorrInches
WHEN SawnOKInches IS NOT NULL THEN SawnOKInches
END AS WIDTH
FROM
StaveHistorySummary
INNER JOIN ProductionLines
ON StaveHistorySummary.fk_ProductionLines = ProductionLines.ProductionLines_NDX
INNER JOIN InspectionSites
ON StaveHistorySummary.fk_InspectionSites = InspectionSites.InspectionSites_NDX
INNER JOIN ProductTypes
ON StaveHistorySummary.fk_ProductTypes = ProductTypes.ProductTypes_NDX
INNER JOIN Inspectors
ON StaveHistorySummary.fk_Inspectors = Inspectors.Inspectors_NDX
INNER JOIN MillProduction
ON inspectionsites.inspectionsites_ndx = MillProduction.fk_inspectionsites
AND productionlines.productionlines_ndx = MillProduction.fk_productionlines
AND producttypes.producttypes_ndx = millproduction.fk_producttypes
WHERE (CAST(CAST(stavehistorysummary.DateMade as date) as datetime) BETWEEN '6/16/2019' AND '6/22/2019')
AND (CAST(CAST(MillProduction.DateMade as date) as datetime) BETWEEN '6/16/2019' AND '6/22/2019')
GROUP BY
StaveHistorySummary.fk_Inspectors
,StaveHistorySummary.fk_InspectionSites
,StaveHistorySummary.fk_ProductionLines
,StaveHistorySummary.fk_ProductTypes
,StaveHistorySummary.DateMade
,StaveHistorySummary.[TimeStamp]
,StaveHistorySummary.StaveHistoryguid
,InspectionSites.SiteAbbr
,Inspectors.Name
,ProductTypes.Product
,ProductionLines.LineName
,CAST(sum(Millproduction.Pieces) as int) AS SumPieces
,CASE
WHEN SapEdgingInches IS NOT NULL THEN SapEdgingInches
WHEN HeartEdgingInches IS NOT NULL THEN HeartEdgingInches
WHEN BothEdgingInches IS NOT NULL THEN BothEdgingInches
WHEN SawnIncorrInches IS NOT NULL THEN SawnIncorrInches
WHEN EqualizedIncorrInches IS NOT NULL THEN EqualizedIncorrInches
WHEN SawnOKInches IS NOT NULL THEN SawnOKInches
END AS WIDTH

Select records when 2 column's data will match

I have two tables as shown below:
-----------------------
|EmpNo|Complaint |
-----------------------
|9091 |Change required|
|9092 |No change |
|9093 |Changes done |
-----------------------
Above table contains employee number and his complaints.
I have one another table which contains employee all kind of details as shown below.
-------------------------------
|EmpNo|EmailID |EmpBossNO|
-------------------------------
|9091 |abc#gmail.com|9092 |
|9092 |xyz#gmail.com|9093 |
|9093 |mno#gmail.com|9099 |
-------------------------------
Here, if Empno:9091 will raise any complain then a mail will send to his boss that the complain is raise by your employee and you have to accept it so I want to get EmailID of employee's boss and for that I want one SQL query. I tried the query shown here, but it doesn't work.
select EmpEmailID
from tblComplaint
inner join tblEmpMaster on tblEmpMaster.EmpNo = tblComplaint.EmpPSNo
where tblComplaint.EmpPSNo = tblEmpMaster.EmpBossNo
I want output like.. if complaint is raised by EmpNo:9091 then it will return EmailID of his boss which is xyz#gmail.com.
You are on the right track with a join between the tblComplaint and tblEmpMaster tables. But, you need an additional join to tblEmpMaster to bring in the boss' email for each employee complaint.
SELECT
c.EmpNo,
c.Complaint,
COALESCE(e2.EmailID, 'NA') AS boss_email
FROM tblComplaint c
INNER JOIN tblEmpMaster e1
ON c.EmpNo = e1.empNo
LEFT JOIN tblEmpMaster e2
ON e1.EmpBossNO = e2.EmpNo;
Demo
I used a left self join above, in case a given employee does not have a boss (e.g. for the highest ranking boss). In this case, I display NA for the boss email.
You should self join tblEmpMaster
select boss.EmpEmailID
from tblComplaint
inner join tblEmpMaster emp on emp.EmpNo = tblComplaint.EmpPSNo
inner join tblEmpMaster boss on boss.EmpNo = emp.EmpBossNO
where tblComplaint.EmpPSNo = 9091
DB Fiddle
you can even use sub queries to get the Email_Id of the boss as shown below
SELECT Email_Id
FROM EMP_Details
WHERE Emp_No IN (
SELECT Boss_Id
FROM Emp_Details) AND
Emp_No IN (
SELECT Emp_No
FROM Emp_Complaints)

SQL Server UNION or JOIN

I am having a bit of problem with JOIN or UNION? Would you help me solve this?
Here is my story.
I have two tables: tbl_inventory and tbl_delivery.
Here is the scenario. Each week I have to match a delivery and an inventory record. For example: on week 1 I have to show, the delivery and inventory for a specific product.
Inventory Date | Week # |Product |inventory qty | delivery qty
----------------------------------------------------------------------------
2018/02/12 | 7 |cheesecake | 30 | 25 |
It is fine I can do that now. The problem arise when I have no delivery or no inventory for that week? Here is my desired output:
Inventory Date | Week # |Product |inventory qty | delivery qty
----------------------------------------------------------------------------
2018/02/12 | 7 |cheesecake | NULL | 25 |
OR
Inventory Date | Week # |Product |inventory qty | delivery qty
----------------------------------------------------------------------------
2018/02/12 | 7 |cheesecake | 30 | NULL |
Would you help me achieve that? Here is my code
select a.CustCode,
b.Material,
b.Qty as deliveryQty,
d.Qty as inventoryQty
from BigEMerchandiser.dbo.tbl_Delivery_H as a
left join BigEMerchandiser.dbo.tbl_Delivery_D as b
on a.TransCtr = b.TransCtr
left join BigEMerchandiser.dbo.tbl_Inventory_H as c
on datepart(wk, a.DtRcv) = datepart(wk, c.DtRcv)
left join BigEMerchandiser.dbo.tbl_Inventory_D as d
on c.TransCtr = d.TransCtr
left join BigEMasterData.dbo.tbl_Materials as e
on b.Material = e.ExtMatGrp
UNION ALL
select a.CustCode,
b.Material,
d.Qty as deliveryQty,
b.Qty as inventoryQty
from BigEMerchandiser.dbo.tbl_Inventory_H as a
left join BigEMerchandiser.dbo.tbl_Inventory_D as b
on a.TransCtr = b.TransCtr
left join BigEMerchandiser.dbo.tbl_Delivery_H as c
on datepart(wk, a.DtRcv) = datepart(wk, c.DtRcv)
left join BigEMerchandiser.dbo.tbl_Delivery_D as d
on c.TransCtr = d.TransCtr
left join BigEMasterData.dbo.tbl_Materials as e
on b.Material = e.ExtMatGrp
I have switched from using joins and union. But still I get the same result.
Here is my inventory table result:
Here is my delivery table result:
Here is the result of my query:
As we can see, there is only one inventory but it still shows 30 on every delivery. I understand that I have used join that is why. Hope you can help me with understand UNIONs and JOIN here. Hope I explained myself clearly. Thankyou. All you suggestions are appreciated.
EDIT
Here is my new query it s outputting what I want. my problem now is how can I add there where statement? for a specific date range:
select a.CustCode,
b.Material,
b.Qty as deliveryQty,
NULL as inventoryQty
from BigEMerchandiser.dbo.tbl_Delivery_H as a
left join BigEMerchandiser.dbo.tbl_Delivery_D as b
on a.TransCtr = b.TransCtr
left join BigEMasterData.dbo.tbl_Materials as e
on b.Material = e.ExtMatGrp
UNION
select v.CustCode,
b.Material,
NULL as deliveryQty,
b.Qty as inventoryQty
from BigEMerchandiser.dbo.tbl_Inventory_H as v
left join BigEMerchandiser.dbo.tbl_Inventory_D as b
on v.TransCtr = b.TransCtr
left join BigEMasterData.dbo.tbl_Materials as e
on b.Material = e.ExtMatGrp
Thanks a lot!
I suspect the problem is UNION which prevents you from seeing your joins result in duplication. You should use UNION ALL, and correct your joins to include Material.
E.g. something like:
left join BigEMerchandiser.dbo.tbl_Inventory_D as d
on c.TransCtr = d.TransCtr
and c.Material = b.Material
How your tables are connected is not immediately clear, but the point is you are looking for a TransCtr in your inventory. TransCtr = 89 has an inventory of 30, it's just the wrong material.

JOIN table multiple times for same columns, from different columns

I've had a search and there are many Questions out there that sound the same but are slightly not covering what I need.
I have the following setup:
Database: Job1, Table: Document
id | rev_desc_id | created_by_id | modified_by_id | checker_id | approver_id
---|-------------|---------------|----------------|------------|------------
1 | 1 | 1 | 1 | 2 | 3
"rev_desc_id" links MySoftware.dbo.Revision_Description.id
"created_by_id", "modified_by_id", "checker_id", "approver_id" link MyCompany.dbo.Person.id
Database: MyCompany, Table: Person
id | first_name | last_name
---|------------|----------
1 | Tom | DeLonge
2 | Mark | Hoppus
3 | Travis | Barker
Database: MySoftware, Table: Revision_Description
id | name
---|------------
1 | Draft
2 | For Comment
I have the following SQL:
SELECT Document.*, Revision_Description.name AS 'Rev Description', CONCAT(Person.first_name, ' ', Person.last_name) AS 'Created By'
FROM Document
INNER JOIN MySoftware.dbo.Revision_Description
ON rev_desc_id=Revision_Description.id
INNER JOIN MyCompany.dbo.Person
ON created_by_id=Person.id
This all works fine, but I'm now at the point where I need to return the other concatenated names for "modified", "checker" and "approver". I'm not sure how to give these specific column names like "AS Created By".
I also have some other columns that need joining to other tables too.
I am pretty new to database design and I'm not trying my best to name and link them all correctly, so apologies if I'm completely wrong with all this.
Any help or suggestions would be greatly appreciated.
Thank you in advance.
For a lookup tables I prefer to use LEFT JOIN, but you can add the Person table N times and use an alias depending on Creator, Checker, ...
SELECT
Document.*,
Revision_Description.name AS 'Rev Description',
CONCAT(C.first_name, ' ', C.last_name) AS 'Created By',
CONCAT(M.first_name, ' ', M.last_name) AS 'Modified By',
CONCAT(K.first_name, ' ', K.last_name) AS 'Checked By'
FROM Document
INNER JOIN MySoftware.dbo.Revision_Description
ON rev_desc_id=Revision_Description.id
LEFT JOIN MyCompany.dbo.Person as C
ON created_by_id=C.id
LEFT JOIN MyCompany.dbo.Person as M
ON modified_by_id=M.id
LEFT JOIN MyCompany.dbo.Person as K
ON checked_id=K.id
SELECT d.*, s.name 'Rev Description',
CONCAT(c.first_name, ' ', c.last_name) CreatedBy,
CONCAT(m.first_name, ' ', m.last_name) ModifiedBy,
CONCAT(k.first_name, ' ', k.last_name) CheckedBy,
CONCAT(a.first_name, ' ', a.last_name) ApprovedBy,
FROM Document d
JOIN MySoftware.dbo.Revision_Description s
ON s.id = d.rev_desc_id
left JOIN MyCompany.dbo.Person c
ON c.id = d.created_by_id
left JOIN MyCompany.dbo.Person m
ON m.id = d.modified_by_id
left JOIN MyCompany.dbo.Person k
ON k.id = d.checker_id
left JOIN MyCompany.dbo.Person a
ON a.id = d.approver_id

EF6 - Generating unneeded nested queries

I have the following tables:
MAIN_TBL:
Col1 | Col2 | Col3
------------------
A | B | C
D | E | F
And:
REF_TBL:
Ref1 | Ref2 | Ref3
------------------
A | G1 | Foo
D | G1 | Bar
Q | G2 | Xyz
I wish to write the following SQL query:
SELECT M.Col1
FROM MAIN_TBL M
LEFT JOIN REF_TBL R
ON R.Ref1 = M.Col1
AND R.Ref2 = 'G1'
WHERE M.Col3 = 'C'
I wrote the following LINQ query:
from main in dbContext.MAIN_TBL
join refr in dbContext.REF_TBL
on "G1" equals refr.Ref2
into refrLookup
from refr in refrLookup.DefaultIfEmpty()
where main.Col1 == refr.Col1
select main.Col1
And the generated SQL was:
SELECT
[MAIN_TBL].[Col1]
FROM (SELECT
[MAIN_TBL].[Col1] AS [Col1],
[MAIN_TBL].[Col2] AS [Col2],
[MAIN_TBL].[Col3] AS [Col3]
FROM [MAIN_TBL]) AS [Extent1]
INNER JOIN (SELECT
[REF_TBL].[Ref1] AS [Ref1],
[REF_TBL].[Ref2] AS [Ref2],
[REF_TBL].[Ref3] AS [Ref3]
FROM [REF_TBL]) AS [Extent2] ON [Extent1].[Col1] = [Extent2].[Ref1]
WHERE ('G1' = [Extent2].[DESCRIPTION]) AND ([Extent2].[Ref1] IS NOT NULL) AND CAST( [Extent1].[Col3] AS VARCHAR) = 'C') ...
Looks like it is nesting a query within another query, while I just want it to pull from the table. What am I doing wrong?
I may be wrong, but it looks like you don't do the same in linq query and sql query, especially on your left joining clause.
I would go for this, if you want something similar to your sql query.
from main in dbContext.MAIN_TBL.Where(x => x.Col3 == "C")
join refr in dbContext.REF_TBL
on new{n = "G1", c = main.Col1} equals new{n = refr.Ref2, c = refr.Col1}
into refrLookup
from r2 in refrLookup.DefaultIfEmpty()
select main.Col1
By the way, it doesn't make much sense to left join on a table which is not present in the select clause : you will just get multiple identical Col1 if there's more than one related item in the left joined table...

Resources