I have an SSRS report that looks at products used in a bill of materials. It lists the items involved, the bill of materials (BOM) they belong to and other various information. I would like to highlight ANY duplicates in the item column without having to sort by item.
Example data:
Level
Item No.
BOM No.
Quantity Per
1
001468
017998
4
1
001850
017998
6
1
017663
017998
2
1
017792
017998
2
2
001468
017663
3
So in the above data, the item # "001468" should get highlighted even though the information in the other columns is different per row.
I am aware of the "Previous" function but I don't want to re-order the item number column so I don't think using that is an option
The report sorts by level so that it first lists all the items in the top level (level 1) followed by the lower levels (2, 3, 4 etc...)
There can be multiple duplicates (not just 2), so any solution will have to factor that in
Would like the duplicate(s) too be highlighted in Bold Red
If more information is needed please let me know.
Edit: More Details added below 08/05/2022
Here is the code I am working with which begins with a recursive CTE:
WITH CTERBOM AS
(
SELECT PBL.[Production BOM No_], PBL.[Version Code], PBL.[No_], PBL.[Quantity per], 1 AS LVL
FROM [DataBaseName$Production BOM Line] PBL
LEFT JOIN [DataBaseName$Production BOM Header Extra] PBHEX ON PBHEX.[No_] = PBL.[Production BOM No_]
WHERE PBL.[Production BOM No_] = '008722' AND PBHEX.[Active Version No_] = PBL.[Version Code]
UNION ALL
SELECT PBL2.[Production BOM No_], PBL2.[Version Code], PBL2.[No_], PBL2.[Quantity per], LVL + 1
FROM [DataBaseName$Production BOM Line] PBL2
INNER JOIN CTERBOM ON CTERBOM.[No_] = PBL2.[Production BOM No_]
)
SELECT
CTERBOM.[LVL] AS [Level],
CTERBOM.[No_] AS [Item No.],
CTERBOM.[Production BOM No_] AS [Production BOM No.],
CTERBOM.[Quantity per] AS [Qty. Per]
FROM CTERBOM
LEFT JOIN [DataBaseName$Production BOM Header Extra] PBHEX ON PBHEX.[No_] = CTERBOM.[Production BOM No_]
GROUP BY
CTERBOM.[LVL],
CTERBOM.[Production BOM No_],
CTERBOM.[No_],
CTERBOM.[Quantity per],
ORDER BY
CTERBOM.[LVL],
CTERBOM.[Production BOM No_],
CTERBOM.[No_]
One way to do this would be to do add a new column to the query, as duplicates = count(*) over (partition by [Item No.]) (insert your actual column name).
Then use that to conditionally highlight the Item No field in the report if the value of the duplicates column is > 1. You would do this by going to the Item No field in the report > properties > fill > fill color > press the expression button and enter something like:
=IIf(Fields!duplicates.Value > 1,"Yellow","Default")
Add this column to your final select:
-- APPROACH 1:
SELECT
CTERBOM.[LVL] AS [Level],
CTERBOM.[No_] AS [Item No.],
count(*) over (partition by CTERBOM.[No_]) as duplicates,
/* ... */
/* APPROACH 2:
if you can't use approach 1 because of other code not currently
shown in the question, you can wrap the entire select in
another select, which will always work:
*/
WITH CTERBOM AS
(
SELECT PBL.[Production BOM No_], PBL.[Version Code], PBL.[No_], PBL.[Quantity per], 1 AS LVL
FROM [DataBaseName$Production BOM Line] PBL
LEFT JOIN [DataBaseName$Production BOM Header Extra] PBHEX ON PBHEX.[No_] = PBL.[Production BOM No_]
WHERE PBL.[Production BOM No_] = '008722' AND PBHEX.[Active Version No_] = PBL.[Version Code]
UNION ALL
SELECT PBL2.[Production BOM No_], PBL2.[Version Code], PBL2.[No_], PBL2.[Quantity per], LVL + 1
FROM [DataBaseName$Production BOM Line] PBL2
INNER JOIN CTERBOM ON CTERBOM.[No_] = PBL2.[Production BOM No_]
)
select level,
[Item No.],
count(*) over (partition by [Item No.]) as duplicates,
[Production BOM No.],
[Qty. Per]
from (
SELECT
CTERBOM.[LVL] AS [Level],
CTERBOM.[No_] AS [Item No.],
CTERBOM.[Production BOM No_] AS [Production BOM No.],
CTERBOM.[Quantity per] AS [Qty. Per]
/* rest of existing query ... */
) t;
Related
I am using inner join in query but I want Subquery instead of join
select [Document No_] as DocumentNo,
ledger.[Posting Date] as Date,
[Sales (LCY)] as Amount,
header.[Customer Reference] as PONo
from [Uneek Clothing Company Ltd$Cust_ Ledger Entry] ledger
inner join [Uneek Clothing Company Ltd$Sales Invoice Header] header on ledger.[Entry No_]=header.[Cust_ Ledger Entry No_]
where [Customer No_] = 'DRC01'
and [Document Type]=2
and [Sales (LCY)]!=0
and ledger.[Posting Date] between '01/01/2019' and '12/31/2019'
order by [Sales (LCY)] asc offset 0 ROWS FETCH NEXT 20 ROWS ONLY
[Entry No_] is foreign key in [Uneek Clothing Company Ltd$Sales Invoice Header] with name [Cust_ Ledger Entry No_]
if you really want to drop the join and use a subquery instead,
it will look something like this.
Since you did not use an table alias for all columns, I had to assume that no other column of table in the subquery is used anywhere else. If that is not the case then this will not work
It will also only work if the subquery returns no more then 1 row, otherwise a subquery cannot be used at all
select [Document No_] as DocumentNo,
ledger.[Posting Date] as Date,
[Sales (LCY)] as Amount,
( select header.[Customer Reference]
from [Uneek Clothing Company Ltd$Sales Invoice Header] header
where ledger.[Entry No_] = header.[Cust_ Ledger Entry No_]
) as PONo
from [Uneek Clothing Company Ltd$Cust_ Ledger Entry] ledger
where [Customer No_] = 'DRC01'
and [Document Type]=2
and [Sales (LCY)]!=0
and ledger.[Posting Date] between '01/01/2019' and '12/31/2019'
order by [Sales (LCY)] asc
offset 0 ROWS FETCH NEXT 20 ROWS ONLY
When trying to convert a datetime field to get rid of NULL's I am getting the error that the datetime cannot be converted.
This query is populating another database where the column datatype is date.
This job runs perfectly fine when not scheduled, but results in an error during the scheduled insert job.
Any ideas?
, (SELECT
CASE
WHEN MIN([Discount Ledger].[Posting Date]) IS NOT NULL
THEN CONVERT(VARCHAR(50), MIN([Discount Ledger].[Posting Date]), 121)
ELSE '-'
END
FROM
[Wings$Discount Ledger Entry] AS "Discount Ledger"
LEFT JOIN
[Wings$Periodic Discount] AS "MixMatchHeader" ON [Discount Ledger].[Offer No_] = [MixMatchHeader].[No_]
LEFT JOIN
[Wings$Periodic Discount Line] AS "MixMatch" ON [MixMatchHeader].[No_] = [MixMatch].[Offer No_]
LEFT JOIN
[Wings$Item_Special Group Link] AS "Special Group" ON [MixMatch].[No_] = [Special Group].[Special Group Code]
LEFT JOIN
[Wings$Store Price Group] AS "Store Price Group" ON [MixMatch].[Price Group] = [Store Price Group].[Price Group Code]
WHERE
[MixMatch].[No_] = [Item Ledger].[Item No_]
AND [MixMatch].[Variant Code] = [Item Ledger].[Variant Code]
AND [Store Price Group].[Store] = [Item Ledger].[Location Code]) AS "Discount Start Date"
You can do this using ISNULL. Since you are looking for the MIN date, I will use GETDATE() as the argument/replacement value for NULL. Unless your data has future dates, then GETDATE() should function as the MAX value. Unless you want the CASE statement to evaluate the NULL values as the MIN. In that case, you can use an empty string '' or '1900-01-01' instead of GETDATE().
, (SELECT
CASE
WHEN
MIN([Discount Ledger].[Posting Date]) IS NOT NULL
THEN CONVERT(varchar(50),MIN(ISNULL([Discount Ledger].[Posting Date],GETDATE())),121)
ELSE '-'
END
FROM [Wings$Discount Ledger Entry] AS "Discount Ledger"
LEFT JOIN [Wings$Periodic Discount] AS "MixMatchHeader" ON [Discount Ledger].[Offer No_] = [MixMatchHeader].[No_]
LEFT JOIN [Wings$Periodic Discount Line] AS "MixMatch" ON [MixMatchHeader].[No_] = [MixMatch].[Offer No_]
LEFT JOIN [Wings$Item_Special Group Link] AS "Special Group" ON [MixMatch].[No_] = [Special Group].[Special Group Code]
LEFT JOIN [Wings$Store Price Group] AS "Store Price Group" ON [MixMatch].[Price Group] = [Store Price Group].[Price Group Code]
WHERE [MixMatch].[No_] = [Item Ledger].[Item No_] AND [MixMatch].[Variant Code] = [Item Ledger].[Variant Code] AND [Store Price Group].[Store] = [Item Ledger].[Location Code])
AS "Discount Start Date"
Hard to explain problem here :)
I need to get a new column I have the amount of lines
F.E. "RIT-17000263-T: 1" would have an extra column "Total Sequences": '9'
"RIT-17000264-T: 1" would be "Total Sequences": '2'
Any help is welcome!:
SELECT DISTINCT
CONCAT(R.[Trip No_],'-', CONCAT('T: ', LEFT(R.[Partial trip Line No_],1))) AS 'TRIP',
R.[File] AS 'FILE',
R.[Sequence No_] AS 'SEQUENCE IN PTRIP'
FROM
[Route] AS R
WHERE
(R.[Trip No_] = 'RIT-17000263'
OR R.[Trip No_] = 'RIT-17000264')
GROUP BY
CONCAT(R.[Trip No_], '-', CONCAT('T: ', LEFT(R.[Partial trip Line No_],1))),
R.[File], R.[Sequence No_]
Perhaps wrap it in a CTE...
with cte as(
SELECT DISTINCT
CONCAT(R.[Trip No_],'-', CONCAT('T: ', LEFT(R.[Partial trip Line No_],1))) AS 'TRIP',
R.[File] AS 'FILE',
R.[Sequence No_] AS 'SEQUENCE IN TRIP'
FROM
[Route] AS R
WHERE
(R.[Trip No_] = 'RIT-17000263'
OR R.[Trip No_] = 'RIT-17000264')
GROUP BY
CONCAT(R.[Trip No_], '-', CONCAT('T: ', LEFT(R.[Partial trip Line No_],1))),
R.[File], R.[Sequence No_])
select
c.TRIP,
c.[FILE],
c.[SEQUENCE IN TRIP],
c2.CT as [Total Sequences]
from
cte c
join (select TRIP, count(TRIP) as CT from cte group by TRIP) c2 on c2.TRIP = c.TRIP
I am using Microsoft SQL Server 2012 and I have this query (below). It returns everything correctly but I cannot figure out how to get only the 4th row to return.
I know how to do it with a simple query but with a query this complex I don't know how to only return the 4th row. Since I am using MS SQL Server, I cannot use Limit/Offset. How and where should I place code to only print the 4th row? I'm stumped. Thanks.
SELECT T.[First Name],
T.[Last Name],
T.[Middle Name],
T.[Country Name],
T.[Designation Name],
Salary.Emp_Salary AS 'Current Salary'
FROM
(
SELECT
Emp_First_Name AS "First Name",
Emp_Last_Name AS "Last Name",
Emp_Middle_Name AS "Middle Name",
Country_Name AS "Country Name",
Desig_Name as "Designation Name",
MAX(Emp_Salary_Change_Year) AS "Time"
FROM Employee_Details
INNER JOIN Country ON Employee_Details.Emp_Country_Id = Country.Country_Id
INNER JOIN State ON Employee_Details.Emp_State_Id = State.State_Id
INNER JOIN Designation ON Employee_Details.Desig_Id = Designation.Desig_Id
INNER JOIN Salary ON Employee_Details.Emp_Id = Salary.Emp_Id
GROUP BY Emp_First_Name, Emp_Last_Name,
Emp_Middle_Name, Country_Name, Desig_Name) AS T
INNER JOIN Salary ON T.Time = Salary.Emp_Salary_Change_Year
ORDER BY [Current Salary];
Use a CTE with ROW_NUMBER()
;WITH Cte AS
(
SELECT Col1, Col2, ...,
ROW_NUMBER() OVER (ORDER BY ...) AS RowNum
FROM Table
)
SELECT *
FROM Cte
WHERE RowNum = 4
You can also, use the OFFSET/FETCH keyword.
SELECT *
FROM yourTable
ORDER by yourSortColumn
OFFSET 3 ROWS -- Skip Three rows.
FETCH FIRST 1 ROW ONLY;
You can use TOP this way (first you select only 4 rown and the ordering desc select 1 row)
select TOP 1 from (
SELECT TOP 4 T.[First Name],
T.[Last Name],
T.[Middle Name],
T.[Country Name],
T.[Designation Name],
Salary.Emp_Salary AS 'Current Salary'
FROM
(
SELECT
........
) AS T
INNER JOIN Salary ON T.Time = Salary.Emp_Salary_Change_Year
ORDER BY [Current Salary])
ORDER BY [Current Salary] DESC
I'm working on aging report for accounts over 30 days and I am joining the "Comment" table because AP wants to see the most recent comment if it exists for a customer.
The comment table can have multiple rows for the same customer for each comment that is attached to that customer with the first record being the oldest comment.
When I join the tables everything works, but it returns the first comment not the latest.
How can I get it to to look for multiple rows for the same customer and then return the most recent comment?
*Note - The comment table does not have dates just a field the starts at 1000 and increases for each new comment row
This is what i have right now:
SELECT
dbo.[Pioneer-CO$Purchase Header].No_,
dbo.[Pioneer-CO$Purchase Line].[Amt_ Rcd_ Not Invoiced],
dbo.[Pioneer-CO$Purch_ Rcpt_ Header].[Posting Date],
dbo.[Pioneer-CO$Comment Line].[Comment],
dbo.[Pioneer-CO$Purchase Header].[Sell-to Customer No_]
FROM
dbo.[Pioneer-CO$Purchase Header]
INNER JOIN
dbo.[Pioneer-CO$Purchase Line] ON dbo.[Pioneer-CO$Purchase Header].No_ = dbo.[Pioneer-CO$Purchase Line].[Document No_]
INNER JOIN
dbo.[Pioneer-CO$Purch_ Rcpt_ Header] ON dbo.[Pioneer-CO$Purchase Header].No_ = dbo.[Pioneer-CO$Purch_ Rcpt_ Header].[Order No_]
INNER JOIN
dbo.[Pioneer-CO$Comment Line] ON dbo.[Pioneer-CO$Purchase Header].[Sell-to Customer No_] = dbo.[Pioneer-CO$Comment Line].[No_]
WHERE
(dbo.[Pioneer-CO$Purch_ Rcpt_ Header].[Posting Date] < DATEADD(day, - 30, GETDATE()))
GROUP BY
dbo.[Pioneer-CO$Purchase Header].No_,
dbo.[Pioneer-CO$Purchase Line].[Amt_ Rcd_ Not Invoiced],
dbo.[Pioneer-CO$Purch_ Rcpt_ Header].[Posting Date],
dbo.[Pioneer-CO$Comment Line].[Comment],
dbo.[Pioneer-CO$Purchase Header].[Sell-to Customer No_]
HAVING
(dbo.[Pioneer-CO$Purchase Line].[Amt_ Rcd_ Not Invoiced] > '0')
ORDER BY
dbo.[Pioneer-CO$Purch_ Rcpt_ Header].[Posting Date] DESC
I would use something like this
select customer.*, lastComment.*
from account
cross apply (select top 1 * from comment where
comment.customerId=customer.customerId order by commentnumber desc) lastComment
where customer.age>30
If you need to include customers without comments use outer apply instead of cross apply
I would use following query:
OUTER APPLY
(select top 1 [Comment] from dbo.[Pioneer-CO$Comment Line] where dbo.[Pioneer-CO$Purchase Header].[Sell-to Customer No_] = dbo.[Pioneer-CO$Comment Line].[No_] order by [Posting Date] desc) Comments
Also, use Comments.[Comment] in the SELECT statement instead of dbo.[Pioneer-CO$Comment Line].[Comment]
The dbo.[Pioneer-CO$Comment Line] table should be OUTER APPLY join in the query. Also, order by comments posting date or incremental ID.
You should look at the ID or primary key, I'd imagine the newer comments have a higher ID. You could join the tables and do a Max(ID) or look for the latest timestamp if you use that on your table.
Looks like you have Customers to Comments relationship is 1 to Many(0).
How about trying something like this,
SELECT TOP 1 Customers.*, Comments.*
FROM Customers
JOIN Customers ON Customers.Id = Comments.Id
ORDER BY Comments.Id DESC
Following Added after Bib's comments
You can also try following
SELECT Customers.*, Comments.*
FROM Comments
JOIN
(SELECT MAX(Id) As CId FROM Comments GROUP BY CustomerId) AS CommentsMAX
ON CommentsMAX.CId = Comments.ID
JOIN
Customers ON Customers.Id = Comments.Id