Distinct values with occurrences count - sql-server

I want to count the number of times a vendor title occurs in a resultset, but if I use COUNT combined with GROUP BY, I only get either a 0 or 1 in the resultset
e.g. my results now look like this:
id vendortitle cnt
184 Hotel 1
198 A3 1
199 Las Vegas 1
200 Hotel-Restaurant 1
1252 Hansen 1
1253 Sunrise 1
1255 NULL 0
1256 Winsel 1
1257 Olde North 1
1258 A Castle 1
1259 A Castle 1
1262 Restaurant Rich 1
1263 NULL 0
1264 NULL 0
1265 NULL 0
1266 NULL 0
1269 My venue 1
1270 My venue 1
1271 My venue 1
1272 My venue 1
But I want this (I don't really actually need the NULL values):
id vendortitle cnt
184 Hotel 1
198 A3 1
199 Las Vegas 1
200 Hotel-Restaurant 1
1252 Hansen 1
1253 Sunrise 1
1255 NULL 5
1256 Winsel 1
1257 Olde North 1
1258 A Castle 2
1262 Restaurant Rich 1
1269 My venue 4
My SQL statement:
SELECT DISTINCT(vendortitle),id,COUNT(vendortitle) as cnt FROM (select ROW_NUMBER() OVER (ORDER BY vendortitle DESC) as RowNum,
id,vendortitle
FROM
(
SELECT
uf.id,coalesce(l.title, a.title) as vendortitle
FROM userfavorites uf
INNER JOIN vendor_photos vp ON uf.objectid = vp.id
LEFT JOIN homes l on vp.objecttype= 1 and vp.objectid = l.id
LEFT JOIN hotels a on vp.objecttype= 2 and vp.objectid = a.id
) as info
) as allinfo
WHERE RowNum > 0 AND RowNum <= 50
GROUP BY vendortitle,RowNum, id

There are a lot of things in your query that you don't need. The derived table isn't really needed, the DISTINCT and ROW_NUMBER either. This should do the work:
SELECT MIN(uf.id) id,
COALESCE(l.title, a.title) as vendortitle,
COUNT(*) as cnt
FROM userfavorites uf
INNER JOIN vendor_photos vp
ON uf.objectid = vp.id
LEFT JOIN homes l
ON vp.objecttype= 1
AND vp.objectid = l.id
LEFT JOIN hotels a
ON vp.objecttype = 2
AND vp.objectid = a.id
GROUP BY COALESCE(l.title, a.title);

Related

Convert rows to column headers with totals

I have the following query:
SELECT
g.Gender,
a.AgeGroup,
count(*) as Count
FROM
client c
INNER JOIN AgeGroup a
ON c.age BETWEEN a.StartRange AND a.EndRange
INNER JOIN Gender G on
C.GenderID = G.GenderID
group by
g.Gender,
a.AgeGroup
order by AgeGroup, Gender
which gives the following results:
Gender AgeGroup Count
Male <=25 4
Unknown <=25 2
Female >35 2223
Male >35 6997
Transgender >35 43
Unknown >35 2
Female 26-35 413
Male 26-35 590
Transgender 26-35 5
What I'm needing to try and do though is convert the Gender column to column headers and include totals.
AgeGroup Male Female Trans Unknown Total
<= 25: 4 0 0 2 6
26 - 35: 590 413 5 0 1008
> 35: 6997 2223 43 2 9265
Total: 7591 2636 48 4 10279
I've got this far:
SELECT *
FROM (
SELECT
g.Gender as [Gender],
a.AgeGroup
FROM
client c
INNER JOIN AgeGroup a
ON c.age BETWEEN a.StartRange AND a.EndRange
INNER JOIN Gender G on
C.GenderID = G.GenderID
) as s
PIVOT
(
COUNT(Gender)
FOR [Gender] IN (Male,Female,Transgender,Unknown)
)AS pvt
which returns this:
AgeGroup Male Female Transgender Unknown
<=25 4 0 0 2
26-35 590 413 5 0
>35 6997 2223 43 2
But I don't have the totals.
Is there a way I can do this?
Try this ..
SELECT *,
(select sum(v)
from
(values(male),
(female),
(transgender),
(unknown))
as val(v)) as total
FROM (
SELECT
g.Gender as [Gender],
a.AgeGroup
FROM
client c
INNER JOIN AgeGroup a
ON c.age BETWEEN a.StartRange AND a.EndRange
INNER JOIN Gender G on
C.GenderID = G.GenderID
) as s
PIVOT
(
COUNT(Gender)
FOR [Gender] IN (Male,Female,Transgender,Unknown)
)AS pvt
For updated requirement:
i recommend putting entire table into Some temp table for readabilty and do this
So your above query would go like this
SELECT *,
(select sum(v)
from
(values(male),
(female),
(transgender),
(unknown))
as val(v)) as total
into #temp
from
rest of pivot query
and then do grouping for total
select
case when grouping(agegroup)=1 then 'total' else agegroup end agegroup,
sum(male) as male,
sum(female) as 'female',
sum(trans) as 'trans',
sum(unknown) as 'unknown',
sum(total) as 'Total'
from #temp
group by
grouping sets
(
(agegroup),
()
)

How to show order fulfilment in a SQL Server 2008 query

I am trying to think of a way on a SQL Server 2008 database to run through a sales order table and get open demand for a part, order it by due date, then look at a purchase order table and fulfill the sales orders by PO, ordering the PO supply by due date as well. At the same time, I need to show what PO(s) are fulfilling the sales order.
For example:
SO table
SO# DueDate Part Number Required QTY
---------------------------------------------
100 9/3/16 1012 2
101 9/12/16 1012 1
107 10/11/16 1012 4
103 10/17/16 1012 7
PO table:
PO# DueDate Part Number Ordered QTY
--------------------------------------------
331 9/1/16 1012 1
362 9/2/16 1012 1
359 9/24/16 1012 5
371 10/1/16 1012 3
380 10/10/16 1012 10
With this data, I would like to see this result:
SO# DueDate Part Number Required QTY PO number QTY Used QTY Remain
--------------------------------------------------------------------------
100 9/3/16 1012 2 331 1 0
100 9/3/16 1012 1 362 1 0
101 9/12/16 1012 1 359 1 4
107 10/11/16 1012 4 359 4 0
103 10/17/16 1012 7 371 3 0
103 10/17/16 1012 7 380 4 6
I have done this sales order fulfillment process before, but not to the point of breaking down what PO(s) are fulfilling the order, only to the point of summing all open supply, then running through and subtracting the supply from each sales order to get a running balance of supply left.
Many thanks in advance for your help.
I found a bit weird solution, hope it helps you. Maybe later I could optimize it, but now I post it as is:
;WITH cte AS (
SELECT 1 as l
UNION ALL
SELECT l+1
FROM cte
WHERE l <= 1000000
), SO_cte AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY DueDate ASC) as rn
FROM SO s
CROSS JOIN cte c
WHERE c.l <= s.[Required QTY]
), PO_cte AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY DueDate ASC) as rn
FROM PO p
CROSS JOIN cte c
WHERE c.l <= p.[Ordered QTY]
), almost_done AS (
SELECT DISTINCT
s.SO#,
s.DueDate,
s.[Part Number],
p.PO#,
s.[Required QTY],
p.[Ordered QTY]
FROM SO_cte s
LEFT JOIN PO_cte p
ON p.rn = s.rn
), final AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY DueDate) AS RN
FROM almost_done
)
SELECT f.SO#,
f.DueDate,
f.[Part Number],
f.[Required QTY],
f.PO#,
CASE WHEN f.[Ordered QTY]>f.[Required QTY]
THEN ISNULL(ABS(f1.[Required QTY]-f1.[Ordered QTY]),f.[Required QTY])
ELSE f.[Ordered QTY] END
as [QTY Used],
f.[Ordered QTY] -
CASE WHEN f1.PO# = f.PO#
THEN f1.[Ordered QTY]
ELSE
CASE WHEN f.[Ordered QTY]>f.[Required QTY]
THEN ISNULL(ABS(f1.[Required QTY]-f1.[Ordered QTY]),f.[Required QTY])
ELSE f.[Ordered QTY] END
END as [QTY Remain]
FROM final f
LEFT JOIN final f1
ON f.RN = f1.RN+ 1
AND (f.SO# = f1.SO# OR f.PO# = f1.PO#)
OPTION(MAXRECURSION 0)
Output for data you provided:
SO# DueDate Part Number Required QTY PO# QTY Used QTY Remain
100 2016-09-03 1012 2 331 1 0
100 2016-09-03 1012 2 362 1 0
101 2016-09-12 1012 1 359 1 4
107 2016-10-11 1012 4 359 4 0
103 2016-10-17 1012 7 371 3 0
103 2016-10-17 1012 7 380 4 6

Performance issue with CTE SQL Server query

We have a table with a parent child relationship, that represents a deep tree structure.
We are using a view with a CTE to query the data but the performance is poor (see code and execution plan below).
Is there any way we can improve the performance?
WITH cte (ParentJobTypeId, Id) AS
(
SELECT
Id, Id
FROM
dbo.JobTypes
UNION ALL
SELECT
e.Id, cte.Id
FROM
cte
INNER JOIN
dbo.JobTypes AS e ON e.ParentJobTypeId = cte.ParentJobTypeId
)
SELECT
ISNULL(Id, 0) AS ParentJobTypeId,
ISNULL(ParentJobTypeId, 0) AS Id
FROM
cte
A quick example of using the range keys. As I mentioned before, hierarchies were 127K points and some sections where 15 levels deep
The cte Builds, let's assume the hier results will be will be stored in a table (indexed as well)
Declare #Table table(ID int,ParentID int,[Status] varchar(50))
Insert #Table values
(1,101,'Pending'),
(2,101,'Complete'),
(3,101,'Complete'),
(4,102,'Complete'),
(101,null,null),
(102,null,null)
;With cteOH (ID,ParentID,Lvl,Seq)
as (
Select ID,ParentID,Lvl=1,cast(Format(ID,'000000') + '/' as varchar(500)) from #Table where ParentID is null
Union All
Select h.ID,h.ParentID,cteOH.Lvl+1,Seq=cast(cteOH.Seq + Format(h.ID,'000000') + '/' as varchar(500)) From #Table h INNER JOIN cteOH ON h.ParentID = cteOH.ID
),
cteR1 as (Select ID,Seq,R1=Row_Number() over (Order by Seq) From cteOH),
cteR2 as (Select A.ID,R2 = max(B.R1) From cteOH A Join cteR1 B on (B.Seq Like A.Seq+'%') Group By A.ID)
Select B.R1
,C.R2
,A.Lvl
,A.ID
,A.ParentID
Into #TempHier
From cteOH A
Join cteR1 B on (A.ID=B.ID)
Join cteR2 C on (A.ID=C.ID)
Select * from #TempHier
Select H.R1
,H.R2
,H.Lvl
,H.ID
,H.ParentID
,Total = count(*)
,Complete = sum(case when D.Status = 'Complete' then 1 else 0 end)
,Pending = sum(case when D.Status = 'Pending' then 1 else 0 end)
,PctCmpl = format(sum(case when D.Status = 'Complete' then 1.0 else 0.0 end)/count(*),'##0.00%')
From #TempHier H
Join (Select _R1=B.R1,A.* From #Table A Join #TempHier B on A.ID=B.ID) D on D._R1 between H.R1 and H.R2
Group By H.R1
,H.R2
,H.Lvl
,H.ID
,H.ParentID
Order By 1
Returns the hier in a #Temp table for now. Notice the R1 and R2, I call these the range keys. Data (without recursion) can be selected and aggregated via these keys
R1 R2 Lvl ID ParentID
1 4 1 101 NULL
2 2 2 1 101
3 3 2 2 101
4 4 2 3 101
5 6 1 102 NULL
6 6 2 4 102
VERY SIMPLE EXAMPLE: Illustrates the rolling the data up the hier.
R1 R2 Lvl ID ParentID Total Complete Pending PctCmpl
1 4 1 101 NULL 4 2 1 50.00%
2 2 2 1 101 1 0 1 0.00%
3 3 2 2 101 1 1 0 100.00%
4 4 2 3 101 1 1 0 100.00%
5 6 1 102 NULL 2 1 0 50.00%
6 6 2 4 102 1 1 0 100.00%
The real beauty of the the range keys, is if you know an ID, you know where it exists (all descendants and ancestors).

Random Order by in SQL Server

I got the data using this query:
SELECT PT.ID AS ProductTypeId,
PT.ProductType,
PTPS.ID AS AssetId,
PTPS.Ordinal AS AssetOrdinal,
CASE
WHEN PTPS.LinkType = 2
THEN
--DS.ServerRootURL + 'Videos/ProductTypes/' +
--PTPSMaterialImage.LinkURL
(
SELECT TOP 1 LinkURL
FROM ProductTypesPblmSolutions
WHERE ProductTypeId = PT.ID
AND LinkType = 1
ORDER BY ID DESC
)
ELSE PTPS.LinkURL
END AS MaterialImage,
ATL.LinkType
FROM ProductTypes PT
INNER JOIN ProductTypesToApps PTA ON PT.ID = PTA.ProductTypeId
INNER JOIN ProductTypesPblmSolutions PTPS ON PTPS.ProductTypeId = PT.ID
INNER JOIN DealerSettings DS ON DS.DealerId = 23
INNER JOIN AttachmentLinkTypes ATL ON ATL.ID = PTPS.LinkType
WHERE PTA.AppId = 3
AND (PT.ID = 202 OR 202 IS NULL)
AND (ISNULL(PTPS.IsDeleted, 0) = 0)
ORDER BY PTPS.Ordinal
Let's talk about the materialimage column. I have to get two different images for this producttype but for now I am getting the same product.
There are lot of linkurls exist for this product. Please refer this query below and its data.
SELECT ProductTypeId,
linkurl,
linktype
FROM ProductTypesPblmSolutions
WHERE ProductTypeId = 202
AND linktype = 1
The same thing I used it as subquery in my Main query
How do I get different images in this column.
I tried with TOP 1 ... ORDER BY NEWID() but it does NOT work.
Just to be clear, the subquery should look like:
(SELECT TOP 1 ptps2.LinkURL
FROM ProductTypesPblmSolutions ptps2
WHERE ptps2.ProductTypeId = PT.Id AND
ptps2.LinkType = 1
ORDER BY NEWID()
)
Note the use of qualified column names and the NEWID() in the ORDER BY.
I recommend always using qualified column names. This is especially true in correlated subqueries, where errors are easy to make and very difficult to find (although that might not be the problem in this particular case).
If you see no effect from this, then I would assume that the else component of the case is being executed, rather than the subquery.
SELECT TOP(1) t.LinkURL
FROM dbo.ProductTypesPblmSolutions t
WHERE t.ProductTypeId = PT.ID
AND t.LinkType = 1
ORDER BY NEWID(), PT.ID -- additional calculation
Example #1:
SELECT TOP(10) s.number, (
SELECT TOP(1) s1.number
FROM [master].dbo.spt_values s1
WHERE s1.[type] = s.[type]
ORDER BY NEWID()
)
FROM [master].dbo.spt_values s
WHERE s.[type] = 'P'
Output:
----------- -----------
0 844
1 844
2 844
3 844
4 844
5 844
6 844
7 844
8 844
9 844
Example #2:
SELECT TOP(10) s.number, (
SELECT TOP(1) s1.number
FROM [master].dbo.spt_values s1
WHERE s1.[type] = s.[type]
ORDER BY NEWID(), s.[type] -- <<<< additional calculation
)
FROM [master].dbo.spt_values s
WHERE s.[type] = 'P'
Output:
----------- -----------
0 428
1 801
2 550
3 1619
4 178
5 17
6 1702
7 683
8 352
9 1844

A group by challenge

Let's say I have this table MyTbl
Record Id_try Id Type IsOk DateOk
1 1 MYDB00125 A 0 NULL
2 1 MYDB00125 B 1 2012-07-19 20:10:05.000
3 1 MYDB00125 A 0 2012-07-25 14:10:05.000
4 2 MYDB00125 A 0 2012-07-19 22:10:05.000
5 1 MYDB00254 B 0 2012-07-19 22:10:05.000
6 1 MYDB00254 A 0 NULL
7 3 MYDB00125 A 1 2012-07-19 22:15:05.000
8 3 MYDB00125 B 1 2012-07-19 22:42:53.000
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 C 0 NULL
And I want a group by that brings me for each Id and Type my last "Id_Try Record".
SELECT Id, MAX(Id_Try), MyTbl.Type, IsOK, MAX(DateOk) from MyTbl
GROUP BY Id, MyTbl.Type, IsOK
Won't do, because It'll bring me the last Id_Try AND the last date (Date of record 3 in the example). And I don't care if its the last date or not, I need the date of the last Id_Try.
Is this only solved by a subselect? or a having clause could do?
This is the result expected:
Record Id_try Id Type IsOk DateOk
5 1 MYDB00254 B 0 2012-07-19 22:10:05.000
6 1 MYDB00254 A 0 NULL
7 3 MYDB00125 A 1 2012-07-19 22:15:05.000
8 3 MYDB00125 B 1 2012-07-19 22:42:53.000
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 B 0 NULL
I think you will need to break this into two pieces:
with maxIDTry as
(
SELECT MAX(Id_try) as maxId, ID
FROM MyTable
GROUP BY ID
)
SELECT * FROM MyTable as mt
INNER JOIN maxIDTry as max
ON mt.id_try = max.maxId AND mt.id = max.id
I think you want this:
select * FROM
(
select *, row_number() over (partition by id,type order by Id_try desc) as position from mytbl
) foo
where position = 1
order by record
http://www.sqlfiddle.com/#!3/95742/5
Your sample result set lists
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 A 0 NULL
But that doesn't make sense since you're saying the ID and the Id_try have the same value. I assume you meant for Id_try to be 2 maybe? Otherwise I think my results match up.
Hope this helps.
SELECT A.Record, A.Id_try, A.Id, A.Type, A.IsOk, A.DateOk
FROM MyTbl A INNER JOIN (
SELECT MAX(Id_Try) Id_Try, Id, B1.Type
from MyTbl B1
GROUP BY Id, B1.Type) AS B
ON A.Id_Try = B.Id_Try AND A.Id = B.Id AND A.Type = B.Type
ORDER BY A.RECORD

Resources