How to use SQL query with havng count here? - sql-server

I having Table(Tbl_Test) with following data.
RecordId BatchName Numbers MQC
1 20150443 321106 0
2 20150430 321107 0
3 20150430 321107 1
4 20150412 321110 2
5 20150430 321118
6 20150430 321120
7 20150432 321120
8 20150430 321126
9 20150432 321127
10 20150430 321129
11 20150431 321129
From the above table I want output like,Numbers columns whose count is greater than 1.
RecordId BatchName Numbers MQC
2 20150430 321107 0
3 20150430 321107 1
6 20150430 321120
7 20150432 321120
10 20150430 321129
11 20150431 321129
I've tried the following select but without success:
select RecordId,BatchName,Numbers,MQC
from Tbl_Test
group by RecordId,BatchName,Numbers,MQC
having count(Numbers)>1

;WITH CTE AS
(
SELECT
RecordId,
BatchName,
Numbers,
MQC,
count(*) over (partition by Numbers) cnt
FROM tbl_test
)
SELECT
RecordId, BatchName, Numbers, MQC
FROM CTE
WHERE cnt > 1

You can use GROUP BY with HAVING and IN.Something like this.
SELECT * FROM Tbl_Test
WHERE Numbers IN
(
SELECT Numbers
FROM Tbl_Test
GROUP BY Numbers
HAVING COUNT(*) > 1
)

One solution would be to use a Common table expression.
Try this:
;With CTE AS
(
SELECT Numbers,
Count(1) As NumberOfRows
FROM Tbl_Test
GROUP BY Numbers
)
SELECT T.*
FROM Tbl_Test T
INNER JOIN CTE ON(T.Numbers = CTE.Numbers)
WHERE NumberOfRows > 1
play with it your self on sql fiddle

Use count on RecordID with group By on MQC.
'Count(RecordId) Group By MQC' should work for you.

Related

How to Sum (MAX values) from different value groups in same column SQL Server

I have a table like this:
Date
Consec_Days
2015-01-01
1
2015-01-03
1
2015-01-06
1
2015-01-07
2
2015-01-09
1
2015-01-12
1
2015-01-13
2
2015-01-14
3
2015-01-17
1
I need to Sum the max value (days) for each of the consecutive groupings where Consec_Days are > 1. So the correct result would be 5 days.
This is a type of gaps-and-islands problem.
There are many solutions, here is one simple one
Get the start points of each group using LAG
Calculate a grouping ID using a windowed conditional count
Group by that ID and take the highest sum
WITH StartPoints AS (
SELECT *,
IsStart = CASE WHEN LAG(Consec_Days) OVER (ORDER BY Date) = 1 THEN 1 END
FROM YourTable t
),
Groupings AS (
SELECT *,
GroupId = COUNT(IsStart) OVER (ORDER BY Date)
FROM StartPoints
WHERE Consec_Days > 1
)
SELECT TOP (1)
SUM(Consec_Days)
FROM Groupings
GROUP BY
GroupId
ORDER BY
SUM(Consec_Days) DESC;
db<>fiddle
with cte as (
select Consec_Days,
coalesce(lead(Consec_Days) over (order by Date), 1) as next
from YourTable
)
select sum(Consec_Days)
from cte
where Consec_Days <> 1 and next = 1
db<>fiddle

How to convert a horizontal table into vertical table - SQL?

I have a table on Snowflake
category
Metric1
Metric2
Metric3
First
1
2
3
Second
4
5
6
And I want my table to be like:
Metrics
First
Second
Metric1
1
4
Metric2
2
5
Metric3
3
6
I have a way of doing this with UNPIVOT function in Snowflake-SQL:
SELECT * FROM my_table
UNPIVOT
(DATA for Metrics in
(
Metric1,
Metric2,
Metric3
)
)
However, it somehow returns to
CATEGORY
METRICS
DATA
FIRST
Metric1
1
FIRST
Metric2
2
FIRST
Metric3
3
SECOND
Metric1
4
SECOND
Metric2
5
SECOND
Metric3
6
which is not something I want.
Could anyone please help me with this in one SQL query without creating a new table?
I think there is a way to solve this issue with UNPIVOT, but I couldn't figure this out. Thank you!
One method is a lateral join and aggregation:
select v.metric,
max(case when t.category = 'First' then v.value end) as first,
max(case when t.category = 'Second' then v.value end) as second
from t cross join lateral
(values ('Metric1', metric1),
('Metric2', metric2),
('Metric3', metric3)
) v(metric, value)
group by v.metric;
You were spot on in your original SQL ... just needed to PIVOT the Category back:
SELECT * FROM
(
SELECT * FROM CTE UNPIVOT
( DATA FOR METRICS IN (METRIC_1, METRIC_2, METRIC_3))
)
PIVOT (SUM (DATA) FOR CATEGORY IN ('FIRST','SECOND') )
Copy|Paste|Run
WITH CTE AS
(SELECT 'FIRST' CATEGORY, 1 METRIC_1 ,2 METRIC_2,3 METRIC_3
UNION
SELECT 'SECOND' CATEGORY, 4 METRIC_1 ,5 METRIC_2,6 METRIC_3)
SELECT * FROM
(
SELECT * FROM CTE UNPIVOT ( DATA FOR METRICS IN (METRIC_1, METRIC_2, METRIC_3))
)
PIVOT (SUM (DATA) FOR CATEGORY IN ('FIRST','SECOND') )

Accumulative Update for previous records

I have table that shows these information
Month NewClients OnHoldClients
5-2017 10 2
6-2017 16 4
7-2017 11 1
8-2017 15 6
9-2017 18 7
I am trying to find the accumulative total for each month
which is
(NewClients - OnHoldClients) + Previous Month Total
Something like this
Month NewClients OnHoldClients Total
5-2017 10 2 8
6-2017 16 4 20
7-2017 11 1 30
8-2017 15 6 39
9-2017 18 7 50
the query i tried to build was something like this but I think should be an easier way to do that
UPDATE MyTable
SET Total = (SELECT TOP 1 Total FROM MyTable B WHERE B.Month < A.Month) + NewClients - OnHoldClients
FROM MyTable A
Before we begin, note the mere fact that you're facing such calculative problem is a symptom that maybe you don't have the best possible design. Normally for this purpose calculated values are being stored along the way as the records are inserted. So i'd say you'd better have a total field to begin with and calculate it as records amass.
Now let's get down to the problem at hand. i composed a query which does that nicely but it's a bit verbose due to recursive nature of the problem. However, it yields the exact expected result:
DECLARE #dmin AS date = (SELECT min(mt.[Month]) from dbo.MyTable mt);
;WITH cte(_Month, _Total) AS (
SELECT mt.[Month] AS _Month, (mt.NewClients - mt.OnHoldClients) AS _Total
FROM dbo.MyTable mt
WHERE mt.[Month] = #dmin
UNION ALL
SELECT mt.[Month] AS _Month, ((mt.NewClients - mt.OnHoldClients) + ccc._Total) AS _Total
FROM dbo.MyTable mt
CROSS APPLY (SELECT cc._Total FROM (SELECT c._Total,
CAST((row_number() OVER (ORDER BY c._Month DESC)) AS int) as _Rank
FROM cte c WHERE c._Month < mt.[Month]) as cc
WHERE cc._Rank = 1) AS ccc
WHERE mt.[Month] > #dmin
)
SELECT c._Month, max(c._Total) AS Total
FROM cte c
GROUP BY c._Month
It is a recursive CTE structure that goes about each record all along the way to the initial month and adds up to the final Total value. This query only includes Month and Total fields but you can easily add the other 2 to the list of projection.
Try this
;WITH CTE([Month],NewClients,OnHoldClients)
AS
(
SELECT '5-2017',10,2 UNION ALL
SELECT '6-2017',16,4 UNION ALL
SELECT '7-2017',11,1 UNION ALL
SELECT '8-2017',15,6 UNION ALL
SELECT '9-2017',18,7
)
SELECT [Month],
NewClients,
OnHoldClients,
SUM(MonthTotal)OVER( ORDER BY [Month]) AS Total
FROM
(
SELECT [Month],
NewClients,
OnHoldClients,
SUM(NewClients-OnHoldClients)OVER(PArtition by [Month] Order by [Month]) AS MonthTotal
FROM CTE
)dt
Result,Demo:http://rextester.com/DKLG54359
Month NewClients OnHoldClients Total
--------------------------------------------
5-2017 10 2 8
6-2017 16 4 20
7-2017 11 1 30
8-2017 15 6 39
9-2017 18 7 50

Create a view using SQL Server with repeating rows and new column

I have a table with the following columns.
EVAL_ID | GGRP_ID | GOAL_ID
1 1 1
2 2 1
2 2 2
3 1 3
I want to create a view with another columns called GOAL_VERSION which has values from 1 to 3. So that each row from the above table should be duplicated 5 times for different GOAL_VERSION numbers. The out put should be like this.
EVAL_ID | GGRP_ID | GOAL_ID |GOAL_VERSION
1 1 1 1
1 1 1 2
1 1 1 3
1 1 1 4
1 1 1 5
2 2 1 1
2 2 1 2
2 2 1 3
2 2 1 4
2 2 1 5
How can I do that. Help me. Thank you.
Is it this you are looking for?
DECLARE #tbl TABLE(EVAL_ID INT,GGRP_ID INT,GOAL_ID INT);
INSERT INTO #tbl VALUES
(1,1,1)
,(2,2,1)
,(2,2,2)
,(3,1,3);
SELECT tbl.*
,x.Nr
FROM #tbl AS tbl
CROSS JOIN (VALUES(1),(2),(3),(4),(5)) AS x(Nr)
EDIT: Varying count of repetition
DECLARE #tbl TABLE(EVAL_ID INT,GGRP_ID INT,GOAL_ID INT);
INSERT INTO #tbl VALUES
(1,1,1)
,(2,2,1)
,(2,2,2)
,(3,1,3);
DECLARE #tblCountOfRep TABLE(CountOfRep INT);
INSERT INTO #tblCountOfRep VALUES(3);
SELECT tbl.*
,y.Nr
FROM #tbl AS tbl
CROSS JOIN (SELECT TOP (SELECT CountOfRep FROM #tblCountOfRep) * FROM(VALUES(1),(2),(3),(4),(5) /*add the max count here*/) AS x(Nr)) AS y
In this case I'd prefer I numbers table...
Take a look at CROSS JOIN. If you make a table that's got one column with the 5 rows you want you can just CROSS JOIN it to get the result you're after.
You can achieve this using a CTE and CROSS APPLY:
;WITH CTE AS
(
SELECT 1 AS GOAL_VERSION
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5
)
SELECT * FROM <your table>
CROSS APPLY CTE
use "with" (cte) with rank clause for creating view.
If you have a numbers table in SQL database, you can cross join your table with the numbers table for numbers between 1 and 5
Here is my SQL solution for your requirement
select
goals.*,
n.i as GOAL_VERSION
from goals, dbo.NumbersTable(1,5,1) n
And here is the modified version with "cross join" as suggested in the comments
select
goals.*,
n.i as GOAL_VERSION
from goals
cross join dbo.NumbersTable(1,5,1) n
You can realize, I used a SQL table-valued function for SQL numbers table
Please create that SQL function using the source codes given in the referred tutorial
I hope it helps,

Get Sum of Count

The View obtains the first three columns. I need to add one more column (totalCount) to the view that obtains the total count:
CId CCId CCount totalCount
1 a 3 6
1 a 3 6
1 b 3 6
1 c 3 6
2 b 2 6
2 b 2 6
2 a 2 6
2 a 2 6
3 v 1 6
How to get the totalCount as 6?
(Business rule for Cid=1 Ccount=3 Cid=2 Ccount=2 Cid=3 Ccount=1 So the totalCount =3+2+1 =6)
SELECT a.CID, a.CCID, a.CCOUNT,
b.TotalCount
FROM Table1 a, (SELECT SUM(DISTINCT cCOunt) TotalCount
FROM Table1) b
SQLFiddle Demo
UPDATE
As Andomar pointed out on the comment, An update has been made on the query,
SELECT a.CID, a.CCID, a.CCOUNT,
b.TotalCount
FROM Table1 a,
(
SELECT SUM(TotalCount) TotalCount
FROM
(
SELECT MAX(cCOunt) TotalCount
FROM Table1
GROUP BY CId
) c
) b
SQLFiddle Demo
With this code I came to the desired result:
select CId
,CCId
,CCount
,(select SUM(a.tcount)
from (select distinct CId ,CCount as tcount
from dbo.Test) as a ) totalcount
from dbo.Test
From your example data, I'm assuming a Cid can only have one, possibly repeated, value of CCount. In that case you can pick a random one (say max) using a group by, and sum those:
select sum(OneCCCount) as TotalCount
from (
select max(CCount) as OneCCCount
from YourTable
group by
CId
) as SubQueryAlias

Resources