Order by 5 consecutive rows alternating between results - sql

I'm trying to select from two categories, but I want to alternate between categories by grouping five of each categories.
Here are the tables
SELECT MC.main_category_id, MC.main_category_name, MC.order_by_num AS MC_Order,
C.category_id, C.category_name, C.order_by_num AS C_Order, C.gift, I.item_id, I.model_num, I.item_title, B.brand_name, I.price, I.suggested_price, i.description
FROM dbo.tblMainCategories AS MC
INNER JOIN dbo.tblCategories AS C ON MC.main_category_id = C.main_category_id
INNER JOIN dbo.tblItemCategories AS IC ON MC.main_category_id = IC.main_category_id
AND C.category_id = IC.category_id
INNER JOIN dbo.tblItems AS I ON IC.ic_item_id = I.item_id
INNER JOIN dbo.tblBrands AS B ON I.brand_id = B.brand_id
WHERE (MC.store_id = 14) AND (IC.store_id = 14) AND I.isActive = 1
And MC.main_category_id in (1,2)
ORDER BY MC.order_by_num, C.order_by_num, I.order_by_num,I.price
How can I sort this result that it should be ordered by 5 of MainCategory 1 then 5 of MainCategory 2 and then 5 of MainCategory 1 and continue 5 of each until the end.
MainCategory 1 has much more items than MainCategory 2. the rest of the MainCategory 1 should also be at the bottom.

You could try something like this. Just be sure your results are order the way you want when inserting them into the SQL tables. Break the query into 2 duplicates that insert the results into some temp tables. Then you can iterate through the results inserting each 5 into a third results table.
Here is an example of the approach I took with a db I had available to me.
create table #result(AccountID int, AccountTypeID int, AccountName varchar(128))
select AccountID, ab.AccountTypeID, AccountName INTO #Temp from AccountBase ab
join AccountType at on ab.AccountTypeId = at.AccountTypeId
where ab.AccountTypeId in (1)
order by AccountName
select AccountID, ab.AccountTypeID, AccountName INTO #Temp2 from AccountBase ab
join AccountType at on ab.AccountTypeId = at.AccountTypeId
where ab.AccountTypeId in (2)
order by AccountName
While ((select count(*) from #Temp) > 0 or (select count(*) from #Temp2) > 0)
begin
If (select count(*) from #Temp) > 0
Begin
insert into #result select Top(5) * from #Temp
delete top(5) from #Temp
End
If (select count(*) from #Temp2) > 0
Begin
insert into #result select Top(5) * from #Temp2
delete top(5) from #Temp2
End
End
select * from #result
drop table #Temp
drop table #Temp2
drop table #result
I believe everything is supported by SQL 2000.

Related

How to add a temp table in SQL server

I am trying to add a temp table to my query so that I can query that temp table, I have searched the internet but I couldn't get a solution.
this is my query
;WITH cte AS (
SELECT ID, g.Name
FROM game.Game g WITH(NOLOCK
WHERE ID IN (SELECT Data FROM system.Split(1, ','))
UNION ALL
SELECT g.ID, g.Name
FROM game.Game g WITH(NOLOCK)
JOIN cte ON g.ParentID = cte.ID
)
SELECT c.ID,
c.Name
FROM cte c
INNER JOIN list.Type gt WITH(NOLOCK) ON c.TypeId = gt.TypeID
WHERE c.ID NOT IN (SELECT Data FROM system.Split(1, ','))
AND c.ID IN (SELECT ID FROM game.code WITH(NOLOCK)
WHERE ID = c.ID
AND StatusCode IN ('OP', 'CL', 'SU')
AND isDisplay = 'True'
AND GETDATE() BETWEEN DisplayStart AND DisplayEnd
AND GETDATE() < ISNULL(ResultDateTime, ResultExpected)
)
which gives me the following when I run it
ID | Name
1111 | BaseBall
2222 |BasketBall
45896 |Relay
now I tried to create a temp table as follows
Create Table #temp(
ID int,
Name varchar
)
;WITH cte AS (
SELECT ID, g.Name
FROM game.Game g WITH(NOLOCK)
WHERE ID IN (SELECT Data FROM system.Split(1, ','))
UNION ALL
SELECT g.ID, g.Name
FROM game.Game g WITH(NOLOCK)
JOIN cte ON g.ParentID = cte.ID
)
insert into #temp // i wanted to set these values in the temp table
SELECT c.ID,
c.Name
FROM cte c
INNER JOIN list.Type gt WITH(NOLOCK) ON c.TypeId = gt.TypeID
WHERE c.ID NOT IN (SELECT Data FROM system.Split(1, ','))
AND c.ID IN (SELECT ID FROM game.code WITH(NOLOCK)
WHERE ID = c.ID
AND StatusCode IN ('OP', 'CL', 'SU')
AND isDisplay = 'True'
AND GETDATE() BETWEEN DisplayStart AND DisplayEnd
AND GETDATE() < ISNULL(ResultDateTime, ResultExpected)
)
every time I try to store this information in the temp table it gives me an error 'Column name or number of supplied values does not match table definition.' But I only have two values in. What am I doing wrong that I cant see?
First, why not just use select into?
IF OBJECT_ID('TempDB..#temp') IS NOT NULL
BEGIN
DROP TABLE #temp
END
select c.ID, c.Name
into #temp
from . . .
Then you don't need to define #temp as a table.
Next, your definition is bad, because Name has only one character. This would be fixed with select into.
However, I don't know why you are getting the particular error you are getting. The numbers of columns appears to match.

DISTINCT return same ID two times wrongly

This is my SQL query:
SELECT DISTINCT(ItemId), TCode, PartNumber,ModelNumber, ItemUOM
FROM #Results
This query returns:
ItemId TCode Source PartNumber ModelNumber ItemUOM
-----------------------------------------------------------------
1024 1000 NULL NULL EA
1024 1000 FLEX FLEX EA
#Result is a temp table I have used left join in that query
Why does SELECT DISTINCT return the same ItemID 1024 twice?
SELECT DISTCINT(I.ItemId),
(DENSE_RANK() OVER(ORDER BY I.ItemId ASC)) AS RowNumber,
(I.TCode), E.Name AS Source,
I.GoldenRecordNumber AS GoldenRecordNo, I.ItemCode AS MMRefNo,
I.ShortDescription AS ShortText, I.LongDescription AS POText,
Suppliers.Description AS Manufacturer, Suppliers.Name AS ManufacturerCode,
Suppliers.Abbreviation AS ManufacturerAbbr,
ItemSuppliers.ReferenceNo AS PartNumber, ItemSuppliers.ReferenceNo AS ModelNumber,
UOM.Name AS ItemUOM, MG.Name AS PSGC,
NM.Noun AS ClassName, NM.LongAbbrevation AS ClassDescription
INTO
#Results
FROM
Items I
LEFT JOIN
ItemSuppliers ON I.ItemId = ItemSuppliers.ItemsId
LEFT JOIN
Suppliers ON ItemSuppliers.ManufacturerId = Suppliers.SupplierId
LEFT JOIN
UnitOfMeasurement UOM ON UOM.UOMId = I.UOMId
LEFT JOIN
MaterialGroup MG ON MG.MaterialGroupId = I.MaterialGroupId
LEFT JOIN
NounModifiers NM ON NM.NounModifierId = I.NounModifierId
LEFT JOIN
AutoClass AC ON AC.ClassName = NM.Noun
LEFT JOIN
ERP E ON E.ERPId = I.ERPName
LEFT JOIN
NounModifierAttributes NMA ON NMA.NounModifierId =
NM.NounModifierId
LEFT JOIN
Attributes A ON A.AttributeId = NMA.AttributeId
LEFT JOIN
ItemAttributes IA ON IA.ItemId = I.ItemId
WHERE
(I.ItemCode LIKE '%'+'2001010088'+'%' )
SELECT 'Int' = COUNT(distinct(ItemId))
FROM #Results
WHERE (TCode IS NOT NULL OR MMRefNo IS NOT NULL)
SELECT DISTINCT(ItemId),
TCode, Source, GoldenRecordNo, MMRefNo, ShortText, POText,
Manufacturer, ManufacturerCode, ManufacturerAbbr, PartNumber, ModelNumber,
ItemUOM, PSGC, ClassName, ClassDescription
FROM
#Results
WHERE
(TCode IS NOT NULL OR MMRefNo IS NOT NULL)
AND RowNumber BETWEEN (1-1)*100 + 1 AND (((1-1) * 100 + 1) + 100) - 1
DROP TABLE #Results
if you are convinced the rows which are selected can be grouped together then it should work fine.
1. but if rows are having different data then distinct will not help.
2. use ltrim,rtrim to remove leading and trailing spaces.
example: distinct(ltrim(rtrim(ItemId)))
this will help if it due to spaces or for junk values
The behavior of DISTINCT works as expected. For instance, you could use GROUP BY clause to group them by ItemId, TCode to get top most records
SELECT
ItemId, TCode,
MAX(PartNumber) PartNumber, MAX(ModelNumber) ModelNumber,
MAX(ItemUOM), ...
FROM #Results
GROUP BY ItemId, TCode
In case any failure in GROUP BY clause use ranking function to assign the rank and get the record based on rank value.

sql comma delimited list of a column in analytical function

I am using SQL server 2008, and I need to make a common delimeted list of a column. I know how to do it, but I need this time while I use analytical function, I mean I don't want to use group by clause.
Since I will also select the records in outer query "where row_num=1"
Here is the query:
SELECT UserId
,ProductList
,Value
FROM
(
SELECT p.UserId
,p.Value
, ROW_NUMBER()OVER (PARTITION BY p.UserId ORDER BY p.RecordCreateDate asc) AS 'row_num'
--here I need a solution OVER (PARTITION BY p.UserId) AS 'ProductList'
FROM Products p
INNER JOIN
Users u
ON p.UserId = u.Id
) result
WHERE result.row_num = 1
Users data:
Id Name ....
1 John
2 Anton
3 Craig
Products data:
Id UserId Name RecordCreateDate Value
1 1 a 21.12.2012 10
2 1 b 11.12.2012 20
3 1 c 01.12.2012 30
4 2 e 05.12.2012 40
5 2 f 17.12.2012 50
6 3 d 21.12.2012 60
7 3 i 31.12.2012 70
I need a result such as:
UserId ProductList Value
1 a,b,c 30
2 e,f 40
3 d,i 60
Thanks for your help
Since you are going to filter on row_num = 1 you need to put your query in a CTE or the likes where you include the extra columns from Products. Then you can build your comma separated string in the outer query using the for XML path trick without using group by.
;WITH C as
(
SELECT p.UserId
, ROW_NUMBER()OVER (PARTITION BY p.UserId ORDER BY p.RecordCreateDate asc) AS 'row_num'
--, Some other fields from Products
FROM Products p
INNER JOIN
Users u
ON p.UserId = u.Id
)
SELECT UserId,
--, Some other fields from Products
--, Build the concatenated list here using for xml path()
FROM C
WHERE C.row_num = 1
Just for completeness. Remove the # symbols for your actual solution.
SET NOCOUNT ON;
CREATE TABLE #users
(
Id INT,
Name VARCHAR(32)
);
INSERT #users VALUES
(1,'John'),
(2,'Anton'),
(3,'Craig');
CREATE TABLE #products
(
Id INT,
UserId INT,
Name VARCHAR(32),
RecordCreateDate DATE,
Value INT
);
INSERT #products VALUES
(1,1,'a','2012-12-21',10),
(2,1,'b','2012-12-11',20),
(3,1,'c','2012-12-01',30),
(4,2,'e','2012-12-05',40),
(5,2,'f','2012-12-17',50),
(6,3,'d','2012-12-21',60),
(7,3,'i','2012-12-31',70);
The query:
;WITH x AS
(
SELECT UserId, Value,
row_num = ROW_NUMBER() OVER
(
PARTITION BY UserId
ORDER BY RecordCreateDate
)
FROM #products
)
SELECT
x.UserId,
u.Name,
ProductList = STUFF((
SELECT ',' + Name
FROM #Products AS p
WHERE p.UserId = x.UserId
FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'varchar(max)'),1,1,''),
x.Value
FROM x
INNER JOIN #users AS u
ON x.UserId = u.Id
WHERE x.row_num = 1;
Then clean up:
DROP TABLE #users, #products;
Results:
UserId Name ProductList Value
1 John a,b,c 30
2 Anton e,f 40
3 Craig d,i 60
I'm not sure what you're asking in the beginning, but this will give you the requested output
SELECT UserId,
STUFF((SELECT ',' + ProductName from Products p WHERE p.UserID = u.UserID FOR XML PATH('')), 1, 1, '') as ProductList
FROM Users u

Find Duplicate Phones using cte by comparing against other groups

I am trying to determine how many duplicate work phones I can find in Group 94 by comparing against all other groups that are active.
Contacts are grouped using GroupId
The ContactTable Only contains ids and NOT Phones
The DetailedContactTable contains phones
The ContactSummaryTable contains Group status
The sql is working by setting rownumber for each duplicate Workphone > 1.
The problem is that is setting the rownumber > 1 for all groups except for 94. I need to know 94 first and foremost. Any idea how I set rownumber > 1 for duplicates in GroupId 94 first?
DECLARE #GroupID Int
SET #GroupID = 94
;WITH cte AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY d.WorkPhone ORDER BY c.id DESC)
AS rownumber
,d.WorkPhone
,c.id
,GroupID
FROM ContactTable c
INNER JOIN DetailedContactTable d
ON c.DetailedContactId = d.id
WHERE c.GroupID IN
(
SELECT id
FROM ContactSummaryTable WHERE id = #GroupID
OR GroupActive = 1
)
AND NOT d.WorkPhone IS NULL
AND d.WorkPhone <> ''
)
SELECT * FROM cte WHERE rownumber > 1
ORDER BY GroupID;
DECLARE #GroupID INT;
SET #GroupID = 94;
WITH BaseGroup
AS
(
SELECT c.GroupID
,d.WorkPhone
,c.id ContactID
FROM ContactTable c
INNER JOIN DetailedContactTable d ON c.DetailedContactId = d.id
WHERE c.GroupID = #GroupID
AND NOT d.WorkPhone IS NULL
AND d.WorkPhone <> ''
),
OtherGroups
AS
(
SELECT
d.WorkPhone
FROM ContactTable c
INNER JOIN DetailedContactTable d ON c.DetailedContactId = d.id
WHERE c.GroupID <> #GroupID
AND NOT d.WorkPhone IS NULL
AND d.WorkPhone <> ''
AND EXISTS (
SELECT *
FROM ContactSummaryTable WHERE id = c.GroupID
AND GroupActive = 1)
)
SELECT a.*
FROM BaseGroup a
INNER JOIN OtherGroups b ON a.WorkPhone = b.WorkPhone
ORDER BY a.WorkPhone
or
SELECT a.*, CASE WHEN b.WorkPhone IS NULL THEN 'no duplicate' ELSE 'duplicate' END [Status]
FROM BaseGroup a
LEFT JOIN OtherGroups b ON a.WorkPhone = b.WorkPhone
ORDER BY a.WorkPhone

Rows not being returned in stored proc

I have two rows in dbo.Members but my stored proc is not returning a count. I can run the query alone like SELECT COUNT(*) FROM dbo.Members WHERE MemberID = 1234 and it returns the count as 2 which is correct.
Why does it not return the rows in my stored proc?
SELECT
ValidCount,
InvalidCount,
(SELECT COUNT(*) FROM dbo.Members WHERE MemberID = #pMemberID) AS 'TotalMembers'
FROM
dbo.Reporting
WHERE
MemberID = #pMemberID
Probably because you don't have entries in Reporting with MemberId = 1234.
Try this:
SELECT COALESCE(validCount, 0) AS validCount,
COALESCE(invalidCount, 0) AS invalidCount,
(
SELECT COUNT(*)
FROM members m
WHERE m.memberId = p.memberId
) AS totalMembers
FROM (
SELECT #pMemberId AS memberId
) p
LEFT JOIN
reporting r
ON r.memberId = p.memberId