Iterated sub sampling against distinct values, union results - sql

I made a SQL fiddle here
I have a table that has for each row: a category, an document id and a ranking.
The categories are ranked within themselves. For each category, I would like to select a sub sample. All the sub samples should be stacked together in a table.
The catch is that I would like to sub sample by iteratively fetching a halved row index among that category, e.g. if a given category has 32 items, then I would like to fetch rows 32, 16, 8, 4, 2, 1.
In my SQL fiddle I was able to do this for one particular category but I can't figure out how to:
a) do it for all categories in [Major Focus Area]
b) union the resulting subsamples into one table
Any hints or help is much appreciated! I am working in TSQL (MS SQL Server)
Sample data (MS Sql):
CREATE TABLE Rank_MajorAreas
([Rank] int, [Major Focus Area] varchar(17), [ID] int)
;
INSERT INTO Rank_MajorAreas
([Rank], [Major Focus Area], [ID])
VALUES
(1, 'Welfare', 71366),
(2, 'Welfare', 70415),
(3, 'Truck Driving', 70423),
(4, 'Peasant''s Office', 74566),
(5, 'Peasant''s Office', 71560),
(6, 'Nail Therapy', 77497),
(7, 'Truck Driving', 76193),
(8, 'Truck Driving', 79226),
(9, 'Truck Driving', 70222),
(10, 'Welfare', 77336),
(11, 'Truck Driving', 70823),
(12, 'Welfare', 77096),
(13, 'Welfare', 71335),
(14, 'Nail Therapy', 73551),
(15, 'Welfare', 72146),
(16, 'Truck Driving', 74023),
(17, 'Welfare', 71546),
(18, 'Nail Therapy', 74755),
(19, 'Peasant''s Office', 77834),
(20, 'Welfare', 75667),
(21, 'Peasant''s Office', 71342),
(22, 'Peasant''s Office', 77457),
(23, 'Peasant''s Office', 77923),
(24, 'Welfare', 76508),
(25, 'Welfare', 75714),
(26, 'Welfare', 73654),
(27, 'Welfare', 75753),
(28, 'Truck Driving', 71481),
(29, 'Truck Driving', 79424),
(30, 'Peasant''s Office', 76143),
(31, 'Truck Driving', 74076),
(32, 'Nail Therapy', 78714),
(33, 'Nail Therapy', 79924),
(34, 'Welfare', 71482),
(35, 'Welfare', 70050),
(36, 'Welfare', 76053),
(37, 'Nail Therapy', 79591),
(38, 'Peasant''s Office', 75197),
(39, 'Nail Therapy', 74104),
(40, 'Welfare', 72891),
(41, 'Truck Driving', 73621),
(42, 'Peasant''s Office', 71713),
(43, 'Welfare', 71979),
(44, 'Peasant''s Office', 71601),
(45, 'Peasant''s Office', 73928),
(46, 'Nail Therapy', 71759),
(47, 'Nail Therapy', 70379),
(48, 'Welfare', 71215),
(49, 'Truck Driving', 70908),
(50, 'Welfare', 71989)
;
Code thus far:
CREATE VIEW MFA AS
SELECT ROW_NUMBER() OVER(ORDER BY fa.[Rank] ASC) AS Row
,*
FROM Rank_MajorAreas AS fa
-- ideally we could make a view per Focus Area
WHERE fa.[Major Focus Area] = 'Welfare'
ORDER BY Row ASC
OFFSET 0 ROWS;
DECLARE #start int
SELECT #start = (SELECT COUNT(*) FROM MFA)
;WITH Sample( Row ) AS
(
Select #start as Row
UNION ALL
SELECT ROUND(Row/2, 0)
FROM Sample
WHERE Row > 0
)
SELECT * FROM MFA AS mfa
INNER JOIN Sample AS s on s.Row = mfa.Row
ORDER BY mfa.Row ASC
Desired Results, where each focus area is subsampled, the subsamples are returned all together as a single result
Row Rank Major Focus Area ID
1 1 Welfare 71366
2 2 Welfare 70415
4 12 Welfare 77096
9 24 Welfare 76508
19 50 Welfare 71989
...
1 6 Nail Therapy 77497
2 14 Nail Therapy 73551
4 32 Nail Therapy 78714
9 47 Nail Therapy 7037

You need to use PARTITION BY on Major Focus Area column in the OVER clause. Following is the modified TSQL
CREATE VIEW MFA AS
SELECT ROW_NUMBER() OVER(PARTITION BY fa.[Major Focus Area] ORDER BY fa.[Rank] ASC) AS Row
,*
FROM Rank_MajorAreas AS fa
-- ideally we could make a view per Focus Area
ORDER BY [Major Focus Area], Row ASC
OFFSET 0 ROWS;
DECLARE #start int
SELECT #start = (SELECT COUNT(*) FROM MFA)
;WITH Sample( Row, fa ) AS
(
Select COUNT(*) as Row, [Major Focus Area] as fa FROM MFA GROUP BY [Major Focus Area]
UNION ALL
SELECT ROUND(Row/2, 0), fa
FROM Sample
WHERE Row > 0
)
SELECT mfa.Row, mfa.Rank, mfa.[Major Focus Area] FROM MFA AS mfa
INNER JOIN Sample AS s on s.Row = mfa.Row and s.fa=mfa.[Major Focus Area]
ORDER BY [Major Focus Area], mfa.Row ASC
SQL fiddle

Related

Get multiple records between particular start and end point in the table

I have table data like below
In the given table, some records are outdated data that is generated by a bug in a system.
I want to remove all the outdated records
Correct data condition:
if itemStatus rows start and end from status 4 and 6 without 13 or 14 status then it is correct. I do not need to delete that row.
Example: Id 18 to 20 that are correct data.
Note: Id 21 and 22 is correct because status 13,14 start after status 6 (id 20)
Incorrect data conditions:
If itemStatus row starts and ends from status 4 and 6, with 13 and 14 status. Then it is incorrect data and I have to delete that from a DB.
Example: 24 and 25 then 29 and 30
My query
IF OBJECT_ID('tempdb..#TempResult') IS NOT NULL DROP TABLE #TempResult
CREATE TABLE #TempResult (
Id int
)
select ItemId
into #TempItemGroup
from Item
group by itemid
declare #SelectedItemId int
while exists (select ItemId from #TempItemGroup)
begin
select #SelectedItemId = (select top 1 ItemId
from #TempItemGroup
order by ItemId asc
)
IF OBJECT_ID('tempdb..#TempSingleItemGroup') IS NOT NULL DROP TABLE #TempSingleItemGroup
SELECT i1.*
into #TempSingleItemGroup
FROM Item i1
WHERE i1.[Id] >= ( SELECT TOP 1 [Id] FROM Item
WHERE [ItemStatus] = 4 and ItemId = #SelectedItemId )
AND i1.[Id] <= ( SELECT TOP 1 [Id] FROM Item
WHERE [ItemStatus] = 6 and ItemId = #SelectedItemId )
INSERT INTO #TempResult (Id) (SELECT Id FROM #TempSingleItemGroup where ItemStatus = 13 or ItemStatus = 14)
IF OBJECT_ID('tempdb..#TempSingleItemGroup') IS NOT NULL DROP TABLE #TempSingleItemGroup
delete #TempItemGroup
where ItemId = #SelectedItemId
end
-- Delete or do other operation if required
IF(EXISTS(SELECT count(Id) FROM #TempResult))
BEGIN
-- write a query to delete the data
select * from #TempResult
END
IF OBJECT_ID('tempdb..#TempResult') IS NOT NULL DROP TABLE #TempResult
IF OBJECT_ID('tempdb..#TempItemGroup') IS NOT NULL DROP TABLE #TempItemGroup
Expected result
There are some differences between screenshot and actual table data that you can find at the end of this question
Screenshot: 24,25,29,30
Table data: 13,14,15 ,26,27, 31,32
I have two queries
My above query is only getting first status which have 4 and 6
status, example Id 24 and 25, and I am unable to get next wrong
data for 29 and 30
I am using while loop that may not a good
practices. Please suggest me a better way to write a query.
Table schema and data
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Item](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ItemId] [int] NOT NULL,
[ItemStatus] [int] NOT NULL,
CONSTRAINT [PK_Item] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Item] ON
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (1, 23, 2)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (2, 23, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (3, 23, 7)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (4, 23, 6)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (5, 23, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (6, 23, 14)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (7, 23, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (8, 23, 6)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (9, 23, 3)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (10, 45, 2)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (11, 45, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (12, 45, 7)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (13, 45, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (14, 45, 14)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (15, 45, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (16, 45, 6)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (17, 45, 3)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (18, 25, 2)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (19, 25, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (20, 25, 7)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (21, 25, 6)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (23, 25, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (24, 25, 14)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (25, 25, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (26, 25, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (27, 25, 14)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (28, 25, 6)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (29, 25, 3)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (30, 25, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (31, 25, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (32, 25, 14)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (33, 24, 6)
GO
SET IDENTITY_INSERT [dbo].[Item] OFF
GO
My reading of your requirement is this:
For each itemId, find rows with itemStatus in (13, 14) that lie between a row with the same itemId and itemStatus 4, and a row with the same itemid and itemStatus 6, in order of id ascending.
Your current requirements do not state whether we should return rows with item status in (13, 14) where there is a prior 4 row, but no subsequent 6 row (the "end" of the itemid group is reached), or what to do if there is a subsequent 6 row, but no prior 4 row (the "start" of the itemid group is reached).
I make the following interpretation: itemStatus 4 opens a "status block". itemStatus 6 closes a "status block". There should be no rows with status 13 or 14 in an open block.
If that is a correct interpretation, all we really need to do is find rows with item status 13 or 14, and then find the nearest prior row in order of id descending with a status of either 4 or 6. If the status of that prior row is 4 then the rows are in an open block. If the status of that prior row is 6, or no prior row can be found, then the rows are not in an open block.
Note: In the comments you mentioned expected results including id 31 and 32. But your sample data does not include any row with id 31 or 32. You have now provided these rows and I have added them to my data.
create table #items
(
Id int primary key,
ItemId int not null,
ItemStatus int not null,
);
insert #items values
(2, 23, 4),
(3, 23, 7),
(4, 23, 6),
(5, 23, 13),
(6, 23, 14),
(7, 23, 4),
(8, 23, 6),
(9, 23, 3),
(10, 45, 2),
(11, 45, 4),
(12, 45, 7),
(13, 45, 13),
(14, 45, 14),
(15, 45, 13),
(16, 45, 6),
(17, 45, 3),
(18, 25, 2),
(19, 25, 4),
(20, 25, 7),
(21, 25, 6),
(23, 25, 13),
(24, 25, 14),
(25, 25, 4),
(26, 25, 13),
(27, 25, 14),
(28, 25, 6),
(29, 25, 3),
(30, 25, 4),
(31, 25, 13),
(32, 25, 14),
(33, 24, 6);
select item13or14.*
from #items item13or14
cross apply (
select top 1 itemStatus
from #items
where itemId = item13or14.itemId
and id < item13or14.id
and itemStatus in (4, 6)
order by id desc
) prior4or6
where item13or14.itemStatus in (13, 14)
and prior4or6.itemStatus = 4;
/* produces:
Id ItemId ItemStatus
13 45 13
14 45 14
15 45 13
26 25 13
27 25 14
31 25 13
32 25 14
*/

Finding top 10 products sold in a year

I have these tables below along with the definition. I want to find top 10 products sold in a year after finding counts and without using aggregation and in an optimized way. I want to know if aggregation is still needed or I can accomplish it without using aggregation. Below is the query. Can anyone suggest a better approach.
CREATE TABLE Customer (
id int not null,
first_name VARCHAR(30),
last_name VARCHAR(30),
Address VARCHAR(60),
State VARCHAR(30),
Phone text,
PRIMARY KEY(id)
);
CREATE TABLE Product (
ProductId int not null,
name VARCHAR(30),
unitprice int,
BrandID int,
Brandname varchar(30),
color VARCHAR(30),
PRIMARY KEY(ProductId)
);
Create Table Sales (
SalesId int not null,
Date date,
Customerid int,
Productid int,
Purchaseamount int,
PRIMARY KEY(SalesId),
FOREIGN KEY (Productid) REFERENCES Product(ProductId),
FOREIGN KEY (Customerid) REFERENCES Customer(id)
)
Sample Data:
insert into
Customer(id, first_name, last_name, address, state, phone)
values
(1111, 'andy', 'johnson', '123 Maryland Heights', 'MO', 3211451234),
(1112, 'john', 'smith', '237 Jackson Heights', 'TX', 3671456534),
(1113, 'sandy', 'fleming', '878 Jersey Heights', 'NJ', 2121456534),
(1114, 'tony', 'anderson', '789 Harrison Heights', 'CA', 6101456534)
insert into
Product(ProductId, name, unitprice, BrandId, Brandname)
values
(1, 'watch',200, 100, 'apple'),
(2, 'ipad', 429, 100, 'apple'),
(3, 'iphone', 799, 100, 'apple'),
(4, 'gear', 300, 110, 'samsung'),
(5, 'phone',1000, 110, 'samsung'),
(6, 'tab', 250, 110, 'samsung'),
(7, 'laptop', 1300, 120, 'hp'),
(8, 'mouse', 10, 120, 'hp'),
(9, 'monitor', 400, 130, 'dell'),
(10, 'keyboard', 40, 130, 'dell'),
(11, 'dvddrive', 100, 130, 'dell'),
(12, 'dvddrive', 90, 150, 'lg')
insert into
Sales(SalesId, Date, CustomerID, ProductID, Purchaseamount)
values (30, '01-10-2019', 1111, 1, 200),
(31, '02-10-2019', 1111, 3, 799),
(32, '03-10-2019', 1111, 2, 429),
(33, '04-10-2019', 1111, 4, 300),
(34, '05-10-2019', 1111, 5, 1000),
(35, '06-10-2019', 1112, 7, 1300),
(36, '07-10-2019', 1112, 9, 400),
(37, '08-10-2019', 1113, 5, 2000),
(38, '09-10-2019', 1113, 4, 300),
(39, '10-10-2019', 1113, 3, 799),
(40, '11-10-2019', 1113, 2, 858),
(41, '01-10-2020', 1111, 1, 400),
(42, '02-10-2020', 1111, 2, 429),
(43, '03-10-2020', 1112, 7, 1300),
(44, '04-10-2020', 1113, 7, 2600),
(45, '05-10-2020', 1114, 7, 1300),
(46, '06-10-2020', 1114, 7, 1300),
(47, '07-10-2020', 1114, 9, 800)
Tried this:
SELECT PCY.Name, PCY.Year, PCY.SEQNUM
FROM (SELECT P.Name AS Name, Extract('Year' from S.Date) AS YEAR, COUNT(P.Productid) AS CNT,
RANK() OVER (PARTITION BY Extract('Year' from S.Date) ORDER BY COUNT(P.Productid) DESC) AS RANK
FROM Sales S inner JOIN
Product P
ON S.Productid = P.Productid
) PCY
WHERE PCY.RANK <= 10;
I am seeing this error:
ERROR: column "p.name" must appear in the GROUP BY clause or be used in an aggregate function
LINE 2: FROM (SELECT P.Name AS Name, Extract('Year' from S.Date) AS ...
^
SQL state: 42803
Character: 52
I don't understand why you don't want to use an aggregate function when you have to aggregate over your data. This query works fine, without any issues on the GROUP BY:
WITH stats AS (
SELECT EXTRACT
( YEAR FROM DATE ) AS y,
P.productid,
P.NAME,
COUNT ( * ) numbers_sold,
RANK ( ) OVER ( PARTITION BY EXTRACT ( YEAR FROM DATE ) ORDER BY COUNT ( * ) DESC ) r
FROM
product
P JOIN sales S ON S.Productid = P.Productid
GROUP BY
1,2
)
SELECT y
, name
, numbers_sold
FROM stats
WHERE r <= 10;
This works because the productid is the primary key that has a functional dependency to the product name.
By the way, tested on version 12, but it should work on older and newer versions as well.

Select duplicate persons with duplicate memberships

SQL Fiddle with schema and my intial attempt.
CREATE TABLE person
([firstname] varchar(10), [surname] varchar(10), [dob] date, [personid] int);
INSERT INTO person
([firstname], [surname], [dob] ,[personid])
VALUES
('Alice', 'AA', '1/1/1990', 1),
('Alice', 'AA', '1/1/1990', 2),
('Bob' , 'BB', '1/1/1990', 3),
('Carol', 'CC', '1/1/1990', 4),
('Alice', 'AA', '1/1/1990', 5),
('Kate' , 'KK', '1/1/1990', 6),
('Kate' , 'KK', '1/1/1990', 7)
;
CREATE TABLE person_membership
([personid] int, [personstatus] varchar(1), [memberid] int);
INSERT INTO person_membership
([personid], [personstatus], [memberid])
VALUES
(1, 'A', 10),
(2, 'A', 20),
(3, 'A', 30),
(3, 'A', 40),
(4, 'A', 50),
(4, 'A', 60),
(5, 'T', 70),
(6, 'A', 80),
(7, 'A', 90);
CREATE TABLE membership
([membershipid] int, [memstatus] varchar(1));
INSERT INTO membership
([membershipid], [memstatus])
VALUES
(10, 'A'),
(20, 'A'),
(30, 'A'),
(40, 'A'),
(50, 'T'),
(60, 'A'),
(70, 'A'),
(80, 'A'),
(90, 'T');
There are three tables (as per the fiddle above). Person table contains duplicates, same people entered more than once, for the purpose of this exercise we assume that a combination of the first name, surname and DoB is enough to uniquely identify a person.
I am trying to build a query which will show duplicates of people (first name+surname+Dob) with two or more active entries in the Person table (person_membership.person_status=A) AND two or more active memberships (membership.mestatus=A).
Using the example from SQL Fiddle, the result of the query should be just Alice (two active person IDs, two active membership IDs).
I think I'm making progress with the following effort but it looks rather cumbersome and I need to remove Katie from the final result - she doesn't have a duplicate membership.
SELECT q.firstname, q.surname, q.dob, p1.personid, m.membershipid
FROM
(SELECT
p.firstname,p.surname,p.dob, count(*) as cnt
FROM
person p
GROUP BY
p.firstname,p.surname,p.dob
HAVING COUNT(1) > 1) as q
INNER JOIN person p1 ON q.firstname=p1.firstname AND q.surname=p1.surname AND q.dob=p1.dob
INNER JOIN person_membership pm ON p1.personid=pm.personid
INNER JOIN membership m ON pm.memberid = m.membershipid
WHERE pm.personstatus = 'A' AND m.memstatus = 'A'
Since you are using SQL Server windows function will be handy for this scenario. The following will give you the expected output.
SELECT firstname,surname,dob,personid,memberid
from(
SELECT firstname,surname,dob,p.personid,memberid
,Rank() over(partition by p.firstname,p.surname,p.dob order by p.personid) rnasc
,Rank() over(partition by p.firstname,p.surname,p.dob order by p.personid desc) rndesc
FROM [StagingGRG].[dbo].[person] p
INNER JOIN person_membership pm ON p.personid=pm.personid
INNER JOIN membership m ON pm.memberid = m.membershipid
where personstatus='A' and memstatus='A')a
where a.rnasc+rndesc>2
You have to add Group by and Having clause to return duplicate items only-
SELECT
person.firstname,person.surname,person.dob
FROM
person, person_membership, membership
WHERE
person.personid=person_membership.personid AND person_membership.memberid = membership.membershipid
AND
person_membership.personstatus = 'A' AND membership.memstatus = 'A'
GROUP BY
person.firstname,person.surname,person.dob
HAVING COUNT(1) > 1

How to fetch the rows with their predefine order in SQL Server?

I have a SQL Server table like this:
MenuID MenuName MenuColor
---------------------------------------
10 Daily Tickets Gray
15 Kids Ticket Dark Pink
20 Group Discount Dark Ash
11 Discount ticket Brown
17 Referral Ticket Beige
22 Frequent visitor Musturd
27 Annual Pass sky blue
25 Kids Pass Pink
24 free Ticket Yellow
This table has lot of records and more columns too..
Desired result - first four Menus should be ordered with pre-defined order (which I mentioned in my trial query) and remaining should be ordered ASC on MenuName column
Desired result set:
MenuID MenuName MenuColor
---------------------------------------
10 Daily Tickets Gray
27 Annual Pass sky blue
22 Frequent visitor Musturd
20 Group Discount Dark Ash
11 Discount ticket Brown
24 free Ticket Yellow
25 Kids Pass Pink
15 Kids Ticket Dark Pink
17 Referral Ticket Beige
This is the query I tried for this:
SELECT *
FROM tMenus m
ORDER BY
(CASE m.MenuName
WHEN 'Daily Tickets' THEN 1
WHEN 'Annual Pass' THEN 2
WHEN 'Frequent visitor' THEN 3
WHEN 'Group Discount' THEN 4
END), m.MenuName ASC;
However, this is not returning the result that I want. Please correct me where I am wrong.
Thanks
Perhaps you just need an else:
ORDER BY (CASE m.MenuName
WHEN 'Daily Tickets' THEN 1
WHEN 'Annual Pass' THEN 2
WHEN 'Frequent visitor' THEN 3
WHEN 'Group Discount' THEN 4
ELSE 5
END) , m.MenuName ASC;
Adding "DisplayOrder" to the actual table...
IF OBJECT_ID('tempdb..#Menue', 'U') IS NOT NULL
DROP TABLE #Menue;
CREATE TABLE #Menue (
MenuID INT NOT NULL PRIMARY KEY,
MenuName VARCHAR(30) NOT NULL,
MenuColor VARCHAR(10) NOT NULL,
DisplayOrder INT NOT NULL
);
INSERT #Menue(MenuID, MenuName, MenuColor, DisplayOrder) VALUES
(10,'Daily Tickets', 'Gray', 100),
(15,'Kids Ticket', 'Dark Pink', 800),
(20,'Group Discount', 'Dark Ash', 400),
(11,'Discount ticket', 'Brown', 500),
(17,'Referral Ticket', 'Beige', 900),
(22,'Frequent visitor', 'Musturd', 300),
(27,'Annual Pass', 'sky blue', 200),
(25,'Kids Pass', 'Pink', 700),
(24,'free Ticket', 'Yellow', 600);
-- Note: I'm leaving gaps in the DisplayOrder values.
-- This makes it easy to add new values and set their
-- values w/o having to adjust existing values.
SELECT
m.MenuID,
m.MenuName,
m.MenuColor
FROM
#Menue m
ORDER BY
m.DisplayOrder;
Edited answer...
IF OBJECT_ID('tempdb..#MenueDisplayOrder', 'U') IS NOT NULL
DROP TABLE #MenueDisplayOrder;
CREATE TABLE #MenueDisplayOrder (
MenueID INT NOT NULL, --add FK to Menues table
DisplayTypeID INT NOT NULL, --add FK to available Types table
DisplayOrder INT NOT NULL
PRIMARY KEY CLUSTERED (DisplayTypeID, MenueID)
);
INSERT #MenueDisplayOrder (MenueID, DisplayTypeID, DisplayOrder) VALUES
(10, 1, 100), (11, 1, 500), (15, 1, 800), (17, 1, 900), (20, 1, 400),
(22, 1, 300), (24, 1, 600), (25, 1, 700), (27, 1, 200),
(27, 2, 100), (25, 2, 500), (24, 2, 800), (20, 2, 900), (17, 2, 400),
(22, 2, 300), (15, 2, 600), (11, 2, 700), (10, 2, 200),
(15, 3, 100), (11, 3, 500), (10, 3, 800), (22, 3, 900), (24, 3, 400),
(17, 3, 300), (20, 3, 600), (27, 3, 700), (25, 3, 200);
SELECT
m.MenuID,
m.MenuName,
m.MenuColor
FROM
#Menue m
JOIN #MenueDisplayOrder mdo
ON m.MenuID = mdo.MenueID
WHERE
mdo.DisplayTypeID = 2 -- alter this value to change the display order.
ORDER BY
mdo.DisplayOrder;

Subqueries With Multiple Tables

Good day, need your help on my Vehicle Inspection Database. You can see below the structure, you can see it also in here http://sqlfiddle.com/#!3/4ab7e . What I need from this is to extract The Number of Vehicles With Atleast One (1) Defect or Violation Per PROJECT. In the schema below The Total for Project 4 = two (2) vehicles AND Project 9 = 1 vehicle.
Columns Needed are [Project_Name],[Vehicle_Type],[yy],[mm],[Total]
-- Vehicle Inspection Database --
-- Vehicle_Type Table
CREATE TABLE VehicleType
([VehicleTypeId] int,
[Type] varchar (36));
INSERT INTO VehicleType ([VehicleTypeId],[Type])
VALUES (1, 'Light Vehicle'),
(2, 'Tanker'),
(3, 'Goods');
-- Car Table
CREATE TABLE Vehicle
([VehicleID] varchar(36),
[PlateNo] varchar(36),
[VehicleTypeId] int,
[Project] int);
INSERT INTO Vehicle ([VehicleID], [PlateNo],[VehicleTypeId], [Project])
VALUES('A57D4151-BD49-4B44-AF10-000F1C298E05', '8112AG', 1, 4),
('C7095628-AE88-4DD0-A4FD-00363EAB767F', '60070 AD2', 2, 9),
('E714CCD7-E56C-46A8-89D5-003CA5BF6094', '68823 AD1', 3, 9);
-- Event Table
CREATE TABLE Event
([EventID] int,
[VehicleID] varchar(36),
[EventTime] smalldatetime,
[TicketStatus] varchar (10)) ;
INSERT INTO Event([EventID], [VehicleID], [EventTime], TicketStatus)
VALUES (1, 'A57D4151-BD49-4B44-AF10-000F1C298E05', '20130701', 'Open'),
(2, 'A57D4151-BD49-4B44-AF10-000F1C298E05', '20130702', 'Close'),
(3, 'A57D4151-BD49-4B44-AF10-000F1C298E05', '20130703', 'Close'),
(4, 'C7095628-AE88-4DD0-A4FD-00363EAB767F','20130705', 'Open'),
(5, 'C7095628-AE88-4DD0-A4FD-00363EAB767F','20130710', 'Open');
-- Event_Defects Table
CREATE TABLE EventDefects
([EventDefectsID] int,
[EventID] int,
[Status] varchar(15),
[DefectID] int) ;
INSERT INTO EventDefects ([EventDefectsID], [EventID], [Status], [DefectID])
VALUES
-- 1st Inspection for PlateNo. 8112AG
(1, 1, 'YES', 1),
(2, 1, 'NO', 2),
(3, 1, 'YES',3),
(4, 1, 'N/A', 4),
(5, 1, 'N/A', 5),
-- 2nd Inspection for PlateNo. 8112AG
(6, 2, 'NO', 1),
(7, 2, 'NO', 2),
(8, 2, 'NO', 3),
(9, 2, 'N/A', 4),
(10,2, 'N/A', 5),
-- 3rd Inspection for PlateNo. 8112AG
(11, 3, 'NO', 1),
(12, 3, 'NO', 2),
(13, 3, 'NO', 3),
(14, 3, 'NO', 4),
(15, 3, 'NO', 5),
-- 1st Inspection for PlateNo. 60070 AD2
(16, 3, 'NO', 1),
(17, 3, 'NO', 2),
(18, 3, 'NO', 3),
(19, 3, 'N/A', 4),
(20, 3, 'N/A', 5);
-- Defects Table
CREATE TABLE Defects
([DefectID] int,
[DefectsName] varchar (36),
[DefectClassID] int) ;
INSERT INTO Defects ([DefectID], [DefectsName], [DefectClassID])
VALUES (1, 'TYRE', 1),
(2, 'BRAKING SYSTEM', 1),
(3, 'MIRRORS AND WINDSCREEN', 2),
(4, 'OVER SPEEDING', 3),
(5, 'NOT WEARING SEATBELTS', 3);
-- Defect_Class Table
CREATE TABLE DefectClass
([Description] varchar (15),
[DefectClassID] int) ;
INSERT INTO DefectClass ([DefectClassID], [Description])
VALUES (1, 'CATEGORY A'),
(2, 'CATEGORY B'),
(3, 'CATEGORY C');
Do all the joins as inner joins... and it'll eliminate records that are empty.
Can you check if this works for you?
SELECT Vehicle.VehicleID from Vehicle
INNER JOIN Event ON Vehicle.VehicleID = Event.VehicleID
INNER JOIN EventDefects ON EventDefects.EventID = Event.EventID
INNER JOIN Defects ON EventDefects.DefectID = Defects.DefectID
GROUP BY Vehicle.VehicleID;