Having trouble with grouping rows - MS SQL 2008 - sql-server

I have a product table which has some duplicate records.
I need to get primarykeys atfer grouped them according to names and types
DECLARE #Products TABLE
(
pkProductId INT,
productName NVARCHAR(500),
productType INT
)
INSERT INTO #Products (pkProductId, productName, productType)
VALUES
(1, 'iphone', 0),
(2, 'iphone', 0),
(3, 'iphone', 1),
(4, 'iphone', 1),
(5, 'iphone', 1)
After I run like tsql
SELECT pr.pkProductId FROM #Products pr
GROUP BY pr.productName, pr.productType
HAVING COUNT(pr.productName) > 1
I Want To Get These IDs
pkProductId
---------------
2
4
5
Thank You For Your Hepls :)

You could use row_number() to get the result:
select pkProductId
from
(
select pkProductId,
productName,
productType,
row_number() over(partition by productName, productType order by pkproductId) rn
from #Products
) d
where rn >1;
See SQL Fiddle with Demo

Related

MSSQL Having Clause, I don't know what is wrong with my query

I am new to MSSQL and I have collided with a wall here, what I am trying to do is to get the maximum value after summing and grouping up the value of the attribute "Quantity". After executing the query I have written below, I get this error "Incorrect syntax near ')'."
Select BookID, Sum(OrderMem.Quantity)
from OrderMem
Group By BookID
Having Sum(OrderMem.Quantity) = (select MAX(Quantity)
from (Select Sum(OrderMem.Quantity)
from OrderMem
group by BookID
)
);
*The table involved is named [OrderMem]
Please help and thanks :)
As it is mentioned in the comments, you forgot to alias Sum(OrderMem.Quantity) as Quantity in the inner most subquery.
But you can simplify your query by sorting the resuts descending and getting only the top row(s):
select top 1 with ties
BookID, Sum(OrderMem.Quantity) qty
from OrderMem
group by BookID
order by qty desc
If you're at SQL server >= 2016 then you can use a common table expression to simplify things
DECLARE #OrderMem table (
BookID int
,
Quantity int
);
INSERT INTO #OrderMem
VALUES
(1, 3),
(1, 2),
(2, 4),
(2, 5),
(3, 3),
(3, 2),
(3, 1)
;WITH
CTE
AS
(
SELECT BookID, SUM(Quantity) Quantity
FROM #OrderMem OrderMem
GROUP BY BookID
)
SELECT TOP 1
BookID, Quantity
FROM CTE
ORDER BY Quantity DESC
Alternatively, as somebody already mentioned, you'd need to alias a column and a result of a select.
select BookID, Sum(OrderMem.Quantity)
from OrderMem
Group By BookID
Having Sum(OrderMem.Quantity) in (select MAX(a.Quantity)
from (Select Sum(OrderMem.Quantity) Quantity
from OrderMem
group by BookID
) a
);

Get top column base on maximum other column using group by?

How to get top column base on maximum other column using group by?
My raw data:
DECLARE #TB TABLE (ID INT, APP VARCHAR(25), PRICE MONEY)
INSERT INTO #TB
VALUES
(1, 'Apple', 10),
(1, 'Banana', 30),
(1, 'Orange', 20),
(2, 'Apple', 20),
(2, 'Banana', 30),
(2, 'Orange', 40)
This what I want:
Explain:
TOP_APP = Banana because MAX(PRICE) GROUP BY ID,
TOTAL = 60 because SUM(PRICE) GROUP BY ID.
You can use ROW_NUMBER and aggregation to achieve your required output-
DEMO HERE
SELECT A.ID,A.App,A.SUM
FROM
(
select *,
SUM(Price) OVER(PARTITION BY ID) SUM,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Price DESC) RN
from #tb
)A
WHERE RN = 1
Demo on db<>fiddle
;WITH cte_TempTable as
(
SELECT Id, app, price,
SUM(Price) OVER(PARTITION BY ID) Total,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Price DESC) Row_Number
FROM #TB
)
SELECT Id, app as TOP_APP, Total
FROM cte_TempTable
WHERE Row_Number = 1
Output
Id TOP_APP Total
1 Banana 60.0000
2 Orange 90.0000
As my assumption you want the result is
SELECT identity (int,1,1) as ID,
APP AS TOP_APP
,SUM(PRICE) AS TOTAL INTO #T
FROM #TB
GROUP BY APP
order by SUM(PRICE)
select * from #t

How to get the incremented value in a column based on the other column in sql

I have the below table records. For Every TranNo I have to increment one in the expected result column. Is it possible?
How to get this result in sqlserver?
I am unable to get the appropriate result
<Expected Result>
1
1
2
3
4
5
6
7
8
I tried:
SELECT BatchNo,
TranNo,
WorkSource
FROM table1 WITH (NOLOCK)
WHERE BatchNo IN ('0000000420', '0000000421', '0000000422')
AND PROCESSDATE = '20190206'
GROUP BY WorkSource,
BATCHNO,
TranNo;
You can try this
create table #temp (WorkSource char(3), BatchNo char(3), TranNo int)
insert into #temp values
('012', '001', 1),
('012', '001', 1),
('012', '001', 2),
('012', '001', 3),
('012', '002', 1),
('012', '002', 2),
('012', '003', 3),
('013', '005', 1),
('013', '005', 2)
SELECT *, Dense_Rank() OVER(ORDER BY BatchNo, TranNo) AS Row_Number
FROM #temp
Try with this:
;WITH LagTranNo AS
(
SELECT
*,
IsDiffTranNo = CASE WHEN TranNo = LAG(TranNo) OVER (ORDER BY WorkSource, BatchNo, TranNo) THEN 0 ELSE 1 END
FROM
YourTable
)
SELECT
L.*,
SUM(L.IsDiffTranNo) OVER (ORDER BY WorkSource, BatchNo, TranNo)
FROM
LagTranNo AS L
I believe you want to add 1 only when the TranNo changes. Need to be careful with the ordering.
Note: LAG with only work with SQL Server 2012+.

how to select and join same table in mssql [duplicate]

I have a simple categories table as with the following columns:
Id
Name
ParentId
So, an infinite amount of Categories can be the child of a category. Take for example the following hierarchy:
I want, in a simple query that returns the category "Business Laptops" to also return a column with all it's parents, comma separator or something:
Or take the following example:
Recursive cte to the rescue....
Create and populate sample table (Please save us this step in your future questions):
DECLARE #T as table
(
id int,
name varchar(100),
parent_id int
)
INSERT INTO #T VALUES
(1, 'A', NULL),
(2, 'A.1', 1),
(3, 'A.2', 1),
(4, 'A.1.1', 2),
(5, 'B', NULL),
(6, 'B.1', 5),
(7, 'B.1.1', 6),
(8, 'B.2', 5),
(9, 'A.1.1.1', 4),
(10, 'A.1.1.2', 4)
The cte:
;WITH CTE AS
(
SELECT id, name, name as path, parent_id
FROM #T
WHERE parent_id IS NULL
UNION ALL
SELECT t.id, t.name, cast(cte.path +','+ t.name as varchar(100)), t.parent_id
FROM #T t
INNER JOIN CTE ON t.parent_id = CTE.id
)
The query:
SELECT id, name, path
FROM CTE
Results:
id name path
1 A A
5 B B
6 B.1 B,B.1
8 B.2 B,B.2
7 B.1.1 B,B.1,B.1.1
2 A.1 A,A.1
3 A.2 A,A.2
4 A.1.1 A,A.1,A.1.1
9 A.1.1.1 A,A.1,A.1.1,A.1.1.1
10 A.1.1.2 A,A.1,A.1.1,A.1.1.2
See online demo on rextester

Row based Condition in Left Join

Is there a way to write a row based condition in Left Join.
If some row not exists based on column condition, then it should take the next first row.
I have the structure below,
create table Report
(
id int,
name varchar(10)
)
create table ReportData
(
report_id int references report(id),
flag bit,
path varchar(50)
)
insert into Report values (1, 'a');
insert into Report values (2, 'b');
insert into Report values (3, 'c');
insert into ReportData values (1, 0, 'xx');
insert into ReportData values (2, 0, 'yy');
insert into ReportData values (2, 1, 'yy');
insert into ReportData values (3, 1, 'zz');
insert into ReportData values (3, 1, 'mm');
I need some output like
1 a 0 xx
2 b 0 yy
3 c 1 zz
You can use ROW_NUMBER for this:
;WITH ReportDate_Rn AS (
SELECT report_id, flag, path,
ROW_NUMBER() OVER (PARTITION BY report_id ORDER BY path) AS rn
FROM ReportDate
)
SELECT t1.id, t1.name, t2.flag, t2.path
FROM Report AS t1
JOIN ReportDate_Rn AS t2 ON t1.id = t2.report_id AND t2.rn = 1
The above query regards as first record of each report_id slice, the one having the alphabetically smallest path. You may amend the ORDER BY clause of the ROW_NUMBER() window function as you wish.
SELECT id,name,flag,path
FROM
(
SELECT Report.id,Report.name,ReportData.flag,ReportData.path,
row_number() over(partition by ReportData.report_id order by flag) as rownum
FROM Report
JOIN ReportData on Report.id = ReportData.report_id
) tmp
WHERE tmp.rownum=1
A simpler alternative to the left join, using rowid and rownum
SELECT id, name, flag, path
FROM report, reportdata
WHERE reportdata.rowid = (SELECT rowid
FROM reportdata
WHERE id = report_id
AND rownum = 1);
Without using row_numner() you can achieve this.
Have a look at this SQL Fiddle
select r.id, r.name, d.flag, d.path from report r
inner join reportdata d
on r.id = d.report_id group by d.report_id
PS: I wasn't believing the result - I was just building the query - haven't used d.report_id in the select clause and it worked. Will be updating this answer once I get the reason why this query worked :)
Use Partition BY:
declare #Report AS table
(
id int,
name varchar(10)
)
declare #ReportData AS table
(
report_id int ,
flag bit,
path varchar(50)
)
insert into #Report values (1, 'a');
insert into #Report values (2, 'b');
insert into #Report values (3, 'c');
insert into #ReportData values (1, 0, 'xx');
insert into #ReportData values (2, 0, 'yy');
insert into #ReportData values (2, 1, 'yy');
insert into #ReportData values (3, 1, 'zz');
insert into #ReportData values (3, 1, 'mm');
;WITH T AS
(
Select
R.id,
r.name,
RD.flag,
RD.path,
ROW_NUMBER () OVER(PARTITION BY R.id ORDER BY R.id) AS PartNo
FROM #Report R
LEFT JOIN #ReportData RD ON R.id=RD.report_id
)
SELECT
T.id,
T.name,
T.flag,
T.path
FROM T WHERE T.PartNo=1

Resources