extending row number in windows function - sql

I am trying to find the top 10 brands and article type on shopping page for etailer.
the logic I am using is as follows:
I am creating a table for both ]using this logic below and storing top 10
WITH CTE AS
(
SELECT shoppingpage_url,
brand,
COUNT(*) AS sp_count
FROM TABLE name
GROUP BY 1,
2
)
SELECT *,
ROW_NUMBER() OVER (PARTITION BY shoppingpage_url ORDER BY sp_count DESC)
AS Top_10_flag
FROM cte
I am doing the same for article type and joining them both.
SELECT a.shoppingpage_url,
a.top_10_flag,
brand,
article_type
FROM dev.top10_Brand a
LEFT JOIN dev.top10_Articletype b
ON a.shoppingpage_url = b.shoppingpage_url
AND a.Top_10_flag = b.Top_10_flag
The problem I am facing is for certain pages its just one brand but multiple article types.
I am missing the article types for the pages with brand counts Top_10_flag not equal to or lesser than Article type'Top_10_flag.
how do I prevent this?
sample data
-- brand data table
shoppingpage_url, brand,sp_count,Top_10_flag
url1,brandd,5,1
url2,branda,17,1
url2,brandb,8,2
url2,brandc,4,3
url3,brande,5,1
-- article type table
shoppingpage_url, article_type,sp_count,Top_10_flag
url1,articletype1,5,1
url1,articletype2,5,1
url1,articletype3,5,1
url2,articletype12,17,1
url2,articletype3,8,2
url3,articletype23,5,1
url3,articletype2,5,1
-----
the result I am getting
shoppingpage_url,Top_10_flag, brand, article_type
url1,1,brandd,articletype1
url2,1,branda,articletype12
url2,2,brandb,articletype3
url2,3,brandc,
url3,1,brande,1articletype23
---------------------------
what i want
url1,1,brandd,articletype1
url1,2,,articletype2
url1,3,,articletype3
url2,1,branda,articletype12
url2,2,brandb,articletype3
url2,3,brandc,
url3,1,brande,1articletype23
url3,2,,1articletype2

Are you looking for a full join?
SELECT COALESCE(b.shoppingpage_url, a.shoppingpage_url) as shoppingpage_url,
COALESCE(b.top_10_flag, a.top_10_flag) as top_10_flag,
b.brand, a.article_type
FROM dev.top10_Brand b FULL JOIN
dev.top10_Articletype a
ON a.shoppingpage_url = b.shoppingpage_url AND
a.Top_10_flag = b.Top_10_flag

Related

SQL - Returning fields based on where clause then joining same table to return max value?

I have a table named Ticket Numbers, which (for this example) contain the columns:
Ticket_Number
Assigned_Group
Assigned_Group_Sequence_No
Reported_Date
Each ticket number could contain 4 rows, depending on how many times the ticket changed assigned groups. Some of these rows could contain an assigned group of "Desktop Support," but some may not. Here is an example:
Example of raw data
What I am trying to accomplish is to get the an output that contains any ticket numbers that contain 'Desktop Support', but also the assigned group of the max sequence number. Here is what I am trying to accomplish with SQL:
Queried Data
I'm trying to use SQL with the following query but have no clue what I'm doing wrong:
select ih.incident_number,ih.assigned_group, incident_history2.maxseq, incident_history2.assigned_group
from incident_history_public as ih
left join
(
select max(assigned_group_seq_no) maxseq, incident_number, assigned_group
from incident_history_public
group by incident_number, assigned_group
) incident_history2
on ih.incident_number = incident_history2.incident_number
and ih.assigned_group_seq_no = incident_history2.maxseq
where ih.ASSIGNED_GROUP LIKE '%DS%'
Does anyone know what I am doing wrong?
You might want to create a proper alias for incident_history. e.g.
from incident_history as incident_history1
and
on incident_history1.ticket_number = incident_history2.ticket_number
and incident_history1.assigned_group_seq_no = incident_history2.maxseq
In my humble opinion a first error could be that I don't see any column named "incident_history2.assigned_group".
I would try to use common table expression, to get only ticket number that contains "Desktop_support":
WITH desktop as (
SELECT distinct Ticket_Number
FROM incident_history
WHERE Assigned_Group = "Desktop Support"
),
Than an Inner Join of the result with your inner table to get ticket number and maxSeq, so in a second moment you can get also the "MAXGroup":
WITH tmp AS (
SELECT i2.Ticket_Number, i2.maxseq
FROM desktop D inner join
(SELECT Ticket_number, max(assigned_group_seq_no) as maxseq
FROM incident_history
GROUP BY ticket_number) as i2
ON D.Ticket_Number = i2.Ticket_Number
)
SELECT i.Ticket_Number, i.Assigned_Group as MAX_Group, T.maxseq, i.Reported_Date
FROM tmp T inner join incident_history i
ON T.Ticket_Number = i.Ticket_Number and i.assigned_group_seq_no = T.maxseq
I think there are several different method to resolve this question, but I really hope it's helpful for you!
For more information about Common Table Expression: https://www.essentialsql.com/introduction-common-table-expressions-ctes/

SQL subqueries/ subqueries within subqueries

I'm trying to learn SQL (through a company guide).
I have a list of invoices in a table and a tax code associated with one.
All of the invoices have one tax code, except number 1000001 which has two (and therefore two records in dbo.InvoiceTaxBreakDown.
The exercise wants me to create the variables TaxCode1 and TaxCode2. All except one record should have 'NULL' in TaxCode2.
This is my code:
SELECT
InvoiceNo,
TaxCode1 =
(
SELECT
TOP 1 T.TaxCode
FROM
dbo.InvoiceTaxBreakDown as T
WHERE
I.InvoiceGUID = T.InvoiceGUID
ORDER BY
T.TaxCode DESC
)
,
TaxCode2 =
(
SELECT
TOP 1 T.TaxCode
FROM
dbo.InvoiceTaxBreakDown as T
WHERE
I.InvoiceGUID = T.InvoiceGUID
ORDER BY
T.TaxCode ASC
)
FROM
dbo.InvoiceTaxBreakDown as I
I'm not sure if I even need to reference two data sources..
Only the first record is correct! Please help.
[Output][1]

SQL Server 2008 R2 - How to filter a group of records with conditional logic?

I have the following dataset:
Each sales order line has an item which can be found in various location areas in our warehouse (UPPER, GROUND, FLOOR). What I want is a way to evaluate each sales order line and then pick one location, based on a condition.
The condition would say, if SO line contains a location with FLOOR, pick only that location, else check if it contains GROUND, then pick that, or if it contains neither ground or floor then return UPPER.
I don't want to see multiple location areas for each SO line. What's all the ways this can be done? I'd imagine some form of using a case statement with a HAVING clause?
This can be done using the row_number function by ordering the location areas based on the conditions.
select *
from (select t.*
,row_number() over(partition by so#
order by case when location_area='Floor' then 1
when location_area='GROUND' then 2
else 3 end) rn
from tablename t
) x
where rn = 1
Select coalesce(f.SO, g.SO, u.SO) SO,
coalesce(f.Line, g.Line, u.Line) Line,
coalesce(f.item_code, g.item_code, u.item_code) item_code,
coalesce(f.item_description, g.item_description, u.item_description) item_description,
coalesce(f.SO_Qty, g.SO_Qty, u.SO_Qty) SO_Qty,
coalesce(f.branch_Number, g.branch_Number, u.branch_Number) branch_Number,
coalesce(f.location_area, g.location_area, u.location_area) location_area
from myTable f
full join myTable g
on f.location_area='floor'
and g.SO = f.So
and g.location_area='ground'
full join myTable u
on u.SO = f.So
and u.location_area='upper'

Joining multiple tables in Access and limiting to Top 1 result

I have three tables that need to be joined in order to get monthly inventory data in return.
Table 1: TargetInventory
Table 2: TargetValue
Table 3: TargetWeight
[TargetInventory] does not change after being added the first time.
[TargetValue] is just a small table that includes prices of various types of metal.
[TargetWeight] is updated monthly as part of our inventory process. We INSERT new data, we never UPDATE old data.
Below is the relationship between these tables. (Sorry, I don't have the reputation points to post an image. Brand new here, so hopefully this makes sense.)
(* = UniqueKey)
--TargetValue-- --TargetInventory-- --TargetWeight--
*MaterialID <===| *TargetID <=====| *ID
Material |===> MaterialID |===> TargetID
PricePerOunce Length RecordDate
Density Width Weight
Thickness
DateInInventory
The TargetWeight table contains multiple records for TargetID (since a new one is added every month at inventory). That's good for me to track historical usage, but for the current inventory value, I only need the most recent TargetWeight.Weight to be returned.
I don't know how to do a CROSS APPLY from within another INNER JOIN, so I'm at a loss for how to do this (without switching to mySQL and just doing a LIMIT 1...)
I think it needs to look something like what's below, but I'm not sure how to finish the query.
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
TargetWeight.ID,
TargetWeight.TargetID AS TargetWeight_TargetID,
TargetWeight.RecordDate,
TargetWeight.Weight
FROM
(TargetValue
INNER JOIN TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
CROSS APPLY (
SELECT TOP 1 *
FROM .....
)
The following query works for me in Access 2010. It uses an INNER JOIN on a subquery to take the place of the CROSS APPLY (which Access SQL doesn't support). It assumes that there will be no more than one [TargetWeight] record for a given (TargetID, RecordDate):
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
LatestWeight.ID,
LatestWeight.TargetID AS TargetWeight_TargetID,
LatestWeight.RecordDate,
LatestWeight.Weight
FROM
(
TargetValue
INNER JOIN
TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
INNER JOIN
(
SELECT tw.*
FROM
TargetWeight AS tw
INNER JOIN
(
SELECT TargetID, MAX(RecordDate) AS LatestDate
FROM TargetWeight
GROUP BY TargetID
) AS latest
ON latest.TargetID=tw.TargetID
AND latest.LatestDate=tw.RecordDate
) AS LatestWeight
ON LatestWeight.TargetID = TargetInventory.TargetID
Alternative approach specifically for Access 2010 or later
If the above query bogs down with a large number of rows in [TargetWeight] then another possible solution for Access 2010+ would be to add a Yes/No field named [Current] to the [TargetWeight] table and use the following After Insert data macro to ensure that only the latest record for each [TargetID] is flagged as [Current]:
Once that is done, the query would simply be
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
TargetWeight.ID,
TargetWeight.TargetID AS TargetWeight_TargetID,
TargetWeight.RecordDate,
TargetWeight.Weight
FROM
(
TargetValue
INNER JOIN
TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
INNER JOIN
TargetWeight
ON TargetInventory.TargetID = TargetWeight.TargetID
WHERE TargetWeight.Current = True;
To maximize performance, the [TargetWeight].[TargetID] and [TargetWeight].[Current] fields should be indexed.
SELECT TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density, Weight.ID,
Weight.TargetID AS TargetWeight_TargetID,
Weight.RecordDate,
Weight.Weight
FROM TargetInventory
INNER JOIN TargetValue ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
CROSS APPLY (
SELECT TOP 1 *
FROM TargetWeight
WHERE TargetID = TargetInventory.TargetID
ORDER BY RecordDate DESC
) AS Weight

SQL query on a condition

I'm writing a query to retrieve translated content. I want it so that if there isn't a translation for the given language id, it automatically returns the translation for the default language, with Id 1.
select Translation.Title
,Translation.Summary
from Translation
where Translation.FkLanguageId = 3
-- If there is no LanguageId of 3, select the record with LanguageId of 1.
I'm working in MS SQL but I think the theory is not DBMS-specific.
Thanks in advance.
This assumes one row per Translation only, based on how you phrased the question. If you have multiple rows per FkLanguageId and I've misunderstood, please let us know and the query becomes more complex of course
select TOP 1
Translation.Title
,Translation.Summary
from
Translation
where
Translation.FkLanguageId IN (1, 3)
ORDER BY
FkLanguageId DESC
You'd use LIMIT in another RDBMS
Assuming the table contains different phrases grouped by PhraseId
WITH Trans As
(
select Translation.Title
,Translation.Summary
,ROW_NUMBER() OVER (PARTITION BY PhraseId ORDER BY FkLanguageId DESC) RN
from Translation
where Translation.FkLanguageId IN (1,3)
)
SELECT *
FROM Trans WHERE RN=1
This assumes the existance of a TranslationKey that associates one "topic" with several different translation languages:
SELECT
isnull(tX.Title, t1.Title) Title
,isnull(tX.Summary, t1.Summary) Summary
from Translation t1
left outer join Translation tX
on tx.TranslationKey = t1.Translationkey
and tx.FkLanguageId = #TargetLanguageId
where t1.FkLanguageId = 1 -- "Default
Maybe this is a dirty solution, but it can help you
if not exists(select t.Title ,t.Summary from Translation t where t.FkLanguageId = 3)
select t.Title ,t.Summary from Translation t where t.FkLanguageId = 1
else
select t.Title ,t.Summary from Translation t where t.FkLanguageId = 3
Since your reference to pastie.org shows that you're looking up phrases or specific menu item names in a table I'm going to assume that there is a phrase ID to identify the phrases in question.
SELECT ISNULL(forn_lang.Title, default_lang.Title) Title,
ISNULL(forn_lang.Summary, default_lang.Summary) Summary
FROM Translation default_lang
LEFT OUTER JOIN Translation forn_lang ON default_lang.PhraseID = forn_lang.PhraseID AND forn_lang.FkLanguageId = 3
WHERE default_lang.FkLanguageId = 1