most frequent occurence - sql

I have a table with transactions and a statement that is giving out the most used creditcards. AMEX, VISA ...
SELECT CARDBRAND,
count(*) as cardused
from INFO c
left join paytb t
on c.CONT_ID = t.CONT_ID
GROUP BY CARDBRAND
ORDER BY 2 desc;
Now I want to add a column with the MERCHNAME of the shops that were most often found in a transaction with the creditcard:
CARDBRAND CARDUSED MERCHNAME
----------------------------------------
AMEX 182345 Gasstation
VISA 70943 ....

SELECT CARDBRAND
,count(*) as cardused
,MERCHNAME
FROM INFO c
LEFT JOIN paytb t
on c.CONT_ID = t.CONT_ID
GROUP BY CARDBRAND,
MERCHNAME
ORDER BY count(*) desc;
suggestion: It is always recommended to use the ColumnName or function in this case in the ORDERBY clause rather than the column number to avoid any confusion.

First, your correct query should be:
select c.cardbrand, count(t.cont_id) as cardused
from info c left join
paytb t
on c.cont_id = t.cont_id
group by c.cardbrand;
Otherwise, you will never get "0" for card brands that are not used.
For the merchant information, you can use window functions:
select cardbrand, total_cardused, merchant
from (select c.cardbrand, t.merchant, count(t.cont_id) as cardused,
sum(count(t.cont_id)) over (partition by c.cardbrand) as total_cardused,
row_number() over (partition by c.cardbrand order by count(t.cont_id) desc) as seqnum
from info c left join
paytb t
on c.cont_id = t.cont_id
group by c.cardbrand, t.merchant
) cm
where seqnum = 1
group by c.cardbrand;

Related

SQL Server aggregate function without group by

I want to include tcon.Inductive_Injection_Hours, tcon.Capacitive_Injection_Hours without applying group by. How can I do that?
SELECT
bp.Serial_Number,
tcon.Serial_Number AS ConverterSerialNumber,
MAX(tcon.Time_Stamp) AS DateStamp,
tcon.Inductive_Injection_Hours,
tcon.Capacitive_Injection_Hours
FROM
dbo.Bypass AS bp
INNER JOIN
dbo.Converter AS c ON bp.Bypass_ID = c.Bypass_ID
INNER JOIN
dbo.Converter_Tel_Data AS tcon ON c.Converter_ID = tcon.Converter_ID
WHERE
(bp.Site_ID = 7)
GROUP BY
bp.Serial_Number, tcon.Serial_Number,
tcon.Inductive_Injection_Hours, tcon.Capacitive_Injection_Hours
ORDER BY
ConverterSerialNumber
I have figured it out.
select [data].Serial_Number,Time_Stamp,Inductive_Injection_Hours,Capacitive_Injection_Hours,b.Serial_Number from Converter_Tel_Data as [data]
inner join dbo.Converter AS c On [data].Converter_ID = c.Converter_ID
inner join dbo.Bypass as b on c.Bypass_ID = b.Bypass_ID
WHERE
(Time_Stamp = (SELECT MAX(Time_Stamp) FROM Converter_Tel_Data WHERE Converter_ID = [data].Converter_ID)) And ([data].Site_ID=7)
ORDER BY [data].Serial_Number
You can use row_number - either in a CTE/derived table or using a trick with TOP 1.
Select Top 1 With Ties
bp.Serial_Number
, tcon.Serial_Number AS ConverterSerialNumber
, tcon.Time_Stamp AS DateStamp
, tcon.Inductive_Injection_Hours
, tcon.Capacitive_Injection_Hours
From dbo.Bypass AS bp
Inner Join dbo.Converter AS c On bp.Bypass_ID = c.Bypass_ID
Inner Join dbo.Converter_Tel_Data AS tcon ON c.Converter_ID = tcon.Converter_ID
Where bp.Site_ID = 7
Order By
row_number() over(Partition By bp.Serial_Number Order By tcon.Time_Stamp desc)
This should return the latest row from the tconn table for each bp.Serial_Number.

By store (number), list the maximum number of store visits made by a customer

The three tables that I'm linking are item_scan_fact, member_dimension and store_dimension. So far this is what I have:
SELECT
store_dimension.store_number,
member_dimension.member_number
COUNT (item_scan_fact.visit_number) AS NumVisits
FROM
member_dimension,
item_scan_fact
INNER JOIN store_dimension
ON item_scan_fact.member_key = member_dimension.member_key
AND item_scan_fact.store_key = store_dimension.store_key
GROUP BY
store_dimension.store_number,
member_dimension.member_number, NumVisits;
On the surface it appears solvable with a couple Common Table Expressions
Does this help point you in the right direction?
WITH s1 -- JJAUSSI: Find the visit_number_count by member_key and store_key
AS
(SELECT isf.member_key
,isf.store_key
-- JJAUSSI: DISTINCT resolves a potential 1:N (one to many) relationship here
,COUNT( DISTINCT isf.visit_number) AS visit_number_count
FROM item_scan_fact isf
GROUP BY isf.member_key
,isf.store_key),
s2 -- JJAUSSI: Find the visit_number_count_max by member_key
AS
(SELECT s1.member_key
,MAX(s1.visit_number_count) AS visit_number_count_max
FROM s1
GROUP BY s1.member_key)
-- JJAUSSI: Use this version to see the list of store_key values
-- that have the visit_number_count_max value. This has the potential
-- to be a 1:N relationship.
SELECT s1.member_key
,md.member_number
,s1.store_key
,sd.store_number
,s1.visit_number_count
FROM s2 INNER JOIN s1
ON s2.member_key = s1.member_key
AND s2.visit_number_count_max = s1.visit_number_count
INNER JOIN store_dimension sd
ON sd.store_key = s1.store_key
INNER JOIN member_dimension md
ON md.member_key = s1.member_key;
If this is what you were going for...congratulations! On to the next query!
If you ultimately are after a single store_key response for each member_key (basically you want to determine the member_key's "primary" store_key) then an additional step is probably needed (depending on your data).
Here are some ideas:
Evaluate the member_key based on some other summable facet of
item_scan_fact (like total price paid?)
If you consider all store_key values of equal merit that have the same visit_number_count_max value for a given member_key, just choose a store_key with MAX or MIN
You would seem to want:
SELECT member_number, MAX(NumVisits)
FROM (SELECT sd.store_number, md.member_number
COUNT(*) AS NumVisits
FROM member_dimension md JOIN
item_scan_fact isf
ON md.member_key = isf.member_key JOIN
store_dimension sd
ON isf.store_key = sd. store_key
GROUP BY sd.store_number, md.member_number
) sm
GROUP BY member_number;
If you want to return both the max and the matching customer number you can apply a Teradata SQL extension, qualify:
SELECT sd.store_number, md.member_number
COUNT(*) AS NumVisits
FROM member_dimension md JOIN
item_scan_fact isf
ON md.member_key = isf.member_key JOIN
store_dimension sd
ON isf.store_key = sd. store_key
GROUP BY sd.store_number, md.member_number
QUALIFY
rank() -- might return multiple rows with the same max, ROW_NUMBER a single row
over (partition by sd.store_number
order by NumVisits desc) = 1

returning only the most recent record in dataset

I have a query returning data for several dates.
I want to return only record with the most recent date in the field SAPOD (the date is in fact CYYMMDD where C=0 before 2000 and 1 after 2000 and I can show this as YYYYMMDD using SAPOD=Case when LEFT(SAPOD,1)=1 then '20' else '19' end + SUBSTRING(cast(sapod as nvarchar(7)),2,7))
here is my query:
SELECT GFCUS, Ne.NEEAN, SCDLE, SAPOD, SATCD,CUS.GFCUN, BGCFN1,
BGCFN2, BGCFN3, SV.SVCSA, SV.SVNA1, SV.SVNA2, SV.SVNA3,
SV.SVNA4, SV.SVNA5, SV.SVPZIP, SV.NONUK
FROM SCPF ACC
INNER JOIN GFPF CUS ON GFCPNC = SCAN
LEFT OUTER JOIN SXPF SEQ ON SXCUS = GFCUS AND SXPRIM = ''
LEFT OUTER JOIN SVPFClean SV ON SVSEQ = SXSEQ
LEFT OUTER JOIN BGPF ON BGCUS = GFCUS AND BGCLC = GFCLC
LEFT OUTER JOIN NEPF NE ON SCAB=NE.NEAB and SCAN=ne.NEAN and SCAS=ne.NEAS
LEFT OUTER JOIN SAPF SA ON SCAB=SAAB and SCAN=SAAN and SCAS=SAAS
WHERE
(SATCD>500 and
scsac='IV' and
scbal = 0 and
scai30<>'Y' and
scai14<>'Y' and
not exists(select * from v5pf where v5and=scan and v5bal<>0))
GROUP BY GFCUS, Ne.NEEAN, SCDLE, SAPOD, SATCD,
CUS.GFCUN, BGCFN1, BGCFN2, BGCFN3, SV.SVCSA,
SV.SVNA1, SV.SVNA2, SV.SVNA3, SV.SVNA4, SV.SVNA5, SV.SVPZIP, SV.NONUK
ORDER BY MAX(SCAN) ASC, SAPOD DESC
I am getting results like the below where there are several transactions by a customer, and we only want to show the data of the most recent transaction:
So how can I show just the most recent transaction? Is this a case where I should use an OUTER APPLY or CROSS APPY?
EDIT:
Sorry I should clarify that I need the most recent date for each of the unique records in the field NEEAN which is the Account number
You can use ROW_NUMBER() as follows:
SELECT
ROW_NUMBER() OVER (PARTITION BY Ne.NEEAN ORDER BY SAPOD DESC) AS [Row],
GFCUS, Ne.NEEAN, SCDLE, SAPOD, SATCD,CUS.GFCUN, BGCFN1,
BGCFN2, BGCFN3, SV.SVCSA, SV.SVNA1, SV.SVNA2, SV.SVNA3,
SV.SVNA4, SV.SVNA5, SV.SVPZIP, SV.NONUK
FROM SCPF ACC
INNER JOIN GFPF CUS ON GFCPNC = SCAN
LEFT OUTER JOIN SXPF SEQ ON SXCUS = GFCUS AND SXPRIM = ''
LEFT OUTER JOIN SVPFClean SV ON SVSEQ = SXSEQ
LEFT OUTER JOIN BGPF ON BGCUS = GFCUS AND BGCLC = GFCLC
LEFT OUTER JOIN NEPF NE ON SCAB=NE.NEAB and SCAN=ne.NEAN and SCAS=ne.NEAS
LEFT OUTER JOIN SAPF SA ON SCAB=SAAB and SCAN=SAAN and SCAS=SAAS
WHERE
(SATCD>500 and
scsac='IV' and
scbal = 0 and
scai30<>'Y' and
scai14<>'Y' and
not exists(select * from v5pf where v5and=scan and v5bal<>0)) and
[Row] = 1
GROUP BY GFCUS, Ne.NEEAN, SCDLE, SAPOD, SATCD,
CUS.GFCUN, BGCFN1, BGCFN2, BGCFN3, SV.SVCSA,
SV.SVNA1, SV.SVNA2, SV.SVNA3, SV.SVNA4, SV.SVNA5, SV.SVPZIP, SV.NONUK
ORDER BY MAX(SCAN) ASC
You could encapsulate this within a subquery if you don't want to return the [Row] column.
you can user row_number to get top 1 row per customer
In the where clause need to return values with pos value as 1
sample query
row_number() over ( partition by GFCUS order by SAPOD desc) as pos

how to get the latest price in sql query

I need get the price of lasted QuoteDate.
Right now i have query like these
SELECT dbo.INMT.Material, dbo.INMT.LastVendor, dbo.INMT.AvgCost, dbo.MSQD.Status, dbo.MSQH.QuoteDate, dbo.MSQD.UnitPrice
FROM dbo.INMT INNER JOIN
dbo.MSQD ON dbo.INMT.MatlGroup = dbo.MSQD.MatlGroup AND dbo.INMT.Material = dbo.MSQD.Material INNER JOIN
dbo.MSQH ON dbo.MSQD.MSCo = dbo.MSQH.MSCo AND dbo.MSQD.Quote = dbo.MSQH.Quote
GROUP BY dbo.INMT.Material, dbo.INMT.LastVendor, dbo.INMT.AvgCost, dbo.MSQD.Status, dbo.MSQD.UnitPrice, dbo.MSQH.QuoteDate
ORDER BY dbo.INMT.Material
and get the following result
and how can i run a query just get the highlighted record.i try to do something like where QuoteDate =max......but maybe my grouyping is not correct.
thanks
So, assuming SQL Server 2005+, you can use a CTE and ROW_NUMBER():
;WITH CTE AS
(
SELECT I.Material,
I.LastVendor,
I.AvgCost,
MD.Status,
MH.QuoteDate,
MD.UnitPrice,
RN = ROW_NUMBER() OVER( PARTITION BY I.Material, I.LastVendor,
I.AvgCost, MD.Status,
MD.UnitPrice
ORDER BY MH.QuoteDate DESC)
FROM dbo.INMT I
INNER JOIN dbo.MSQD MD
ON I.MatlGroup = MD.MatlGroup
AND I.Material = MD.Material
INNER JOIN dbo.MSQH MH
ON MD.MSCo = MH.MSCo
AND MD.Quote = MH.Quote
)
SELECT Material,
LastVendor,
AvgCost,
Status,
QuoteDate,
UnitPrice
FROM CTE
WHERE RN = 1
Use HAVING QuoteDate=max... after the order by clause.

How get specific rows in grouped result

i need to group some data but because there are 4 store images , sql query return 4 result for every store. How can i get only one for a store by using sql query ?
select s.name,si.SHOP_IMG_PATH,count(*) amount from stab t
inner join shop s on (s.shop_id = t.shop_id)
inner join SHOP_IMG si on (s.shop_id= si.SHOP_ID)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name,si.SHOP_IMG_PATH
order by 3 desc,1 asc
As you see below image there a re 4 images so query can give random image
You are grouping by s.name, si.SHOP_IMG_PATH it will consider all possible combination of s.name, si.SHOP_IMG_PATH as separate you need to keep group by only s.name
Try this
SELECT a.NAME, a.PATH, a.AMOUNT
FROM (select
s.name AS 'NAME', si.SHOP_IMG_PATH AS 'PATH', count(*) AS 'AMOUNT',
ROW_NUMBER() OVER(PARTITION BY s.name
ORDER BY type si.SHOP_IMG_PATH) AS rk
from
stab t
inner join shop s on (s.shop_id = t.shop_id)
inner join SHOP_IMG si on (s.shop_id= si.SHOP_ID)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name
order by 3 desc,1 asc) a
WHERE a.rk = 1;
Alternative
You will get result but this is just a workaround and easy alternative to your problem but not a good one.
select s.name AS 'NAME', min(si.SHOP_IMG_PATH) AS 'PATH', count(*) AS 'AMOUNT',
from
stab t
inner join shop s on (s.shop_id = t.shop_id)
inner join SHOP_IMG si on (s.shop_id= si.SHOP_ID)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name
order by 3 desc,1 asc
This second query will return result as per your need
group by s.name, si.SHOP_IMG_PATH
You're telling it to differentiate them according to SHOP_IMG_PATH. Hence, it shows 4 results, one for each of those.
You'll have to drop SHOP_IMG_PATH from the select clause, if you won't let it use it.
Edit
Got your comment. What you're looking for is random aggregation. This is achieved diferently on different SQL engines. Google around for the one you're using.
If it's Oracle, as indicated by the question tag, here
I solved my problem by using below query,
select s.name,t.shop_id,(select min(SHOP_IMG_PATH) from SHOP_IMG si where shop_id =t.shop_id),count(*) amount from stab t
inner join shop s on (s.shop_id = t.shop_id)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name,t.shop_id
order by 4 desc,1 asc