SQL Server - Compare ordered columns from multiple tables - sql

I have three tables full of item observations, each with say the following columns:
Table2015: ItemName, ItemCount
Table2014: ItemName, ItemCount
Table2013: ItemName, ItemCount
and I'd like to get the 3 highest Counts for each ItemName from Table2015 with a special column that in the report that flags the row if the highest Count for that ItemName in Table2015 is greater than the highest Count for it in Table2014 and Table2013.
I have the following to get the high counts from Table2015, I'm not sure how to proceed to get what I need. Should I use another CTE with the other tables and join it in the final select somehow?
with counts as (
select e.ItemName, e.ItemCount, row_number() over (partition by e.ItemName order by cast(e.ItemCount as int) desc) as rk
from Table2015 e where e.ItemCount <> 'X')
select s.*,
from counts s
where s.rk<4
order by s.ItemName,s.rk;

As long as item names are consistent between years, you just need to join to the other tables
with counts as (
select e.ItemName, e.ItemCount, row_number() over (partition by e.ItemName order by cast(e.ItemCount as int) desc) as rk
from Table2015 e where e.ItemCount <> 'X')
select s.ItemName
, s.ItemCount
, CASE WHEN CAST(t15.ItemCount AS INT) > ISNULL(CAST(t14.ItemCount AS INT), 0) THEN 1 ELSE 0 END AS GreaterThan2014
, CASE WHEN CAST(t15.ItemCount AS INT) > ISNULL(CAST(t13.ItemCount AS INT), 0) THEN 1 ELSE 0 END AS GreaterThan2013
from counts s
inner join counts t15 ON s.ItemName = t15.ItemName and t15.rk = 1
left join (
select ItemName, MAX(CASE WHEN IsNumeric(ItemCount) = 1 THEN CAST(ItemCount AS INT) ELSE -1 END)
from Table2014
where ItemCount <> 'X'
group by ItemName
) t14 on s.ItemName = t14.ItemName
left join (
select ItemName, MAX(CASE WHEN IsNumeric(ItemCount) = 1 THEN CAST(ItemCount AS INT) ELSE -1 END)
from Table2013
where ItemCount <> 'X'
group by ItemName
) t13 on s.ItemName = t13.ItemName
where s.rk<4
order by s.ItemName,s.rk;
Also, you really shouldn't have an 'X' as a possibility in a count field. If you're counting something it should be typed as an INT.

Related

Put together two selects into one

Could you help me put the second select into first one? I need calculate rate of type in first select. Second select works good.
First select:
WITH "global" AS (
SELECT
m.id
,json_build_array(
ce.payload->>'Name',
ce.payload->>'Date',
ce.payload->>’Type,
ce.payload->>’Rate’,
row_number() over (partition by m.id order by ce.payload->>’Date’ desc)) as "value"
FROM public."events" ce
LEFT OUTER JOIN "external"."mapping" m
ON ce.id=m.id
WHERE ce.type IN ('cs_calls','pc_calls')
AND coalesce(ce.payload ->> 'Name', '')!=''
AND m.id IS NOT NULL
)
SELECT
id,
value
FROM “global”
Second select:
select
id,
cast(issue as float)/cast(total_count as float) as Rate
from (select
id,
sum(case when type='Issue' then 1 else 0 end) as issue,
count(*) total_count
from events
GROUP BY id)
If Id is the way to join this tables then you can try the following
select
g.id,
g.value,
((issue * 1.0) / total_count) as Rate
from
(
select
id,
sum(case when type='Issue' then 1 else 0 end) as issue,
count(*) total_count
from events
group by
id
) e
join global g
on e.id = g.id

Take precedence on a specific value from a table

For each person's distinct record that has a toyota,
only take toyota and filter out that person's other cars
else bring all cars.
The actual script will not match my logic above. I was trying to simplify my question by using random names and car brands, but the objective was the same since I wanted to get a specific address code and filter out the rest if it did exist for other vendor names (see below). Thank you, GMB.
GPMEM.dbo.PM00200 a -- Vendor Master
LEFT JOIN GPMEM.dbo.PM30200 b -- Historical/Paid Transactions
ON a.VENDORID = b.VENDORID
LEFT JOIN GPMEM.dbo.PM20000 c -- Open/Posted Transactions
ON a.VENDORID = c.VENDORID
LEFT JOIN (
SELECT d.*,
rank() over(
partition by d.VENDORID
order by case when d.ADRSCODE = 'ACH' THEN 0 ELSE 1 END
)rn
FROM GPMEM.dbo.PM00300 d
) d -- Vendor Address Master
ON a.VENDORID = d.VENDORID
WHERE
d.rn = 1
You can use window functions:
select colA, colB
from (
select
t.*,
rank() over(
partition by colA
order by case when colB = 'Toyota' then 0 else 1 end
) rn
from mytable t
) t
where rn = 1
The trick likes in the order by clause in the over() clause of window function rank(): if a person has a Toyota, it will be ranked first, and their (possible) other cars will be ranked second. If it has no Toyota, all their car will be ranked first.
You can do this with filtering logic:
select t.*
from t
where t.colb = 'toyota' or
not exists (select 1 from t t2 where t2.cola = t.cola and t2.colb = 'toyota');
If I were to use window functions for this, I would simply count the toyotas:
select t.*
from (select t.*,
sum(case when colb = 'toyota' then 1 else 0 end) over (partition by cola) as num_toyotas
from t
) t
where colb = 'toyota' or num_toyotas = 0;

Fetch the top nine rows and then get a tenth row with the total of everything else

I want to fetch nine rows of the count of experts in the country and the name of the country ordered in descending order by count of experts. For the tenth row I want to add a row that shows the total number of experts from all other countries.
Here is my code:
SELECT count(expert_id) as total_expert, cc.country_name
FROM expertsdb.ci_experts_master cem
INNER JOIN ci_city cct ON cct.city_id = cem.city_
INNER JOIN ci_country cc ON cc.country_id = cct.country_id
WHERE cem.city_ IS NOT NULL
order by total_expert
limit 9 desc
If I understand correctly, you want an "other" category after the first 9. You can use window functions:
SELECT (CASE WHEN seqnum <= 9 THEN country_name ELSE 'rest' END) as country_name,
SUM(total_expert)
FROM (SELECT cc.country_name, count(*) as total_expert,
ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) as seqnum
FROM expertsdb.ci_experts_master cem JOIN
ci_city cct
ON cct.city_id = cem.city_ JOIN
ci_country cc
ON cc.country_id = cct.country_id
WHERE cem.city_ IS NOT NULL
) c
GROUP BY (CASE WHEN seqnum <= 9 THEN country_name ELSE 'rest' END)
ORDER BY seqnum ;

Group row when no serial on serial table

Is it possible to group the SQL query result when the item column has no serial list in serial table? Currently I split the column qty to row so the user can select serial 1 by 1. Here's my query:
SELECT row = ROW_NUMBER() over (ORDER BY t.PARENT), t.PARENT, t.BOMNO, t.COMPONENT, o.Qty, t.UNIT, t.COMPBOMNO, t.ISSERIAL, t.ISLOT
FROM (SELECT ICBOMD.ITEMNO AS [PARENT],
ICBOMD.BOMNO,
ICBOMD.COMPONENT,
ICBOMD.QTY,
ICBOMD.UNIT,
ICBOMD.COMPBOMNO,
ISNULL(ICITEM.SERIALNO, 0) AS [ISSERIAL],
ISNULL(ICITEM.LOTITEM, 0) AS [ISLOT]
FROM ICBOMH LEFT OUTER JOIN
ICBOMD
ON ICBOMH.ITEMNO = ICBOMD.ITEMNO AND ICBOMH.BOMNO = ICBOMD.BOMNO LEFT OUTER JOIN
ICITEM
ON ICITEM.ITEMNO = ICBOMD.COMPONENT
WHERE ICITEM.STOCKITEM = 1 AND ICBOMD.ITEMNO = 'GAM-001' AND ICBOMD.BOMNO = 'P1'
) t CROSS APPLY
(SELECT 1
FROM master..spt_values v
WHERE v.type = 'P' AND v.number < t.QTY
) o(Qty)
For example the COMPONENT GAM-COMP02 has no serial on the serial table. It should be group by and the qty will become 2.
Below query is how I retrieved serial:
SELECT SERIALNUM AS [Serial Number], LOCATION AS [Location],
CONVERT(DATE, CONVERT(VARCHAR, STOCKDATE)) AS [Stock Date], STATUS AS [Available]
FROM ICXSER
WHERE ITEMNUM = 'GAM-COMP02'
You may apply Serial number like that
select row_number() over (order by (select 100)) as Slno, * from table
Note: But this will assign row_number indeterminate ordering.
For this line It should be group by and the qty will become 2. it is better to apply group by.
select COMPONENT , count(COMPONENT) as Count from table group by COMPONENT

cross join in query itself to match to see if it is not a last record

I am trying to get a record to match if its sortorder is not the last one in the complete recordset within a query itself
tried this query it gives me the min and count but what i am trying to get
WITH s AS (
SELECT MyGroup, Count(MyGroup) AS [Count],
RANK() OVER (ORDER BY Count(MyGroup)) AS [rasc],
RANK() OVER (ORDER BY Count(MyGroup) DESC) AS [rdesc]
FROM MyTable
GROUP BY (MyGroup)
)
SELECT
CASE
WHEN [rasc] = 1 THEN 'Min'
ELSE 'Max'
END AS 'Agg',
[MyGroup],
[Count]
FROM s
WHERE [rasc] = 1 OR [rdesc] = 1