Unable to group data in a table - sql

Id | MenuName | vc_Link | SubMenu1 | IsMainMenu | TypeOfMenu
-----------------------------------------------------------------------
1 | Home | NULL | NULL | 1 | 0
2 | Projects | NULL | NULL | 1 | 0
4 | Pr1 | NULL | 2 | 0 | 1
5 | Homesub | NULL | 1 | 0 | 1
6 | Pr1Sub1 | NULL | 4 | 0 | 2
The above is my table structure.
MenuName is names of menus and submenus
SubMenu1 is that submenus belong to a paticular menu whos id is saved as submenu1
MainMenu is a bit to know whether it is a menu or submenu.
typeofmenu is that
0 means main menu
1 means submenu
2 means submenu's submenu
Now my problem is i want to display it as below
1 Home
5 HomeSub
2 Projects
4 Pr1
6 Pr1Sub1
Id | MenuName | vc_Link | SubMenu1 | IsMainMenu | TypeOfMenu
-----------------------------------------------------------------------
1 | Home | NULL | NULL | 1 | 0
5 | HomeSub | NULL | 1 | 0 | 1
2 | Projects | NULL | NULL | 1 | 0
4 | Pr1 | NULL | 2 | 0 | 1
6 | Pr1Sub1 | NULL | 4 | 0 | 2
How to group like this?
Only after grouping like this i can make the result of this query as a tree structure showing menus and its submenus.

Something like this:
with menu_tree (id, menuname, level, sort_path) as (
select id,
cast(menuname as varchar(max)),
1 as level,
cast(id as varchar(max)) as sort_path
from menus
where submenu1 is null
union all
select m.id,
cast(replicate('_', p.level * 2) + m.menuname as varchar(max)) as menuname,
p.level + 1,
p.sort_path + '_' + cast(m.id as varchar(max))
from menus m
join menu_tree p on p.id = m.submenu1
)
select id, menuname
from menu_tree
order by sort_path;
SQLFiddle: http://sqlfiddle.com/#!3/6c4ba/1

Related

How to insert records based on another table value

I have the following three tables:
Permission
| PermissionId | PermissionName |
+--------------+----------------+
| 1 | A |
| 2 | B |
| 3 | C |
| 100 | D |
Group
| GroupId | GroupLevel | GroupName |
+---------+------------+----------------------+
| 1 | 0 | System Administrator |
| 7 | 0 | Test Group 100 |
| 8 | 20 | Test Group 200 |
| 9 | 20 | test |
| 10 | 50 | TestGroup01 |
| 11 | 51 | TestUser02 |
| 12 | 52 | TestUser03 |
GroupPermission
| GroupPermissionId | FkGroupId | FkPermissionId |
+-------------------+-----------+----------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 1 | 4 |
I need to insert records into GroupPermission table, if table Group, GroupLevel column have 0
then I need to take its GroupId and need to insert values to GroupPermission table as that particular id and 100.
In order to above sample table records, I need to insert the following two records to GroupPermission table,
| FkGroupId | FkPermissionId |
+-----------+----------------+
| 1 | 100 |
| 7 | 100 |
How can I do it
This question is not very clear and I can only assume the value 100 is a static value and that you don't actually have foreign keys as the names of the columns imply. Also, you really should avoid reserved words like "Group" for object names. It makes things more difficult and confusing.
The simple version of your insert might look like this.
insert GroupPermission
(
FkGroupId
, FkPermissionId
)
select g.GroupId
, 100
from [Group] g
where g.GroupLevel = 0
--EDIT--
Since you want to only insert those rows that don't already exist you can use NOT EXISTS like this.
select g.GroupId
, 100
from [Group] g
where g.GroupLevel = 0
AND NOT EXISTS
(
select *
from GroupPermission gp
where gp.FkGroupId = g.GroupId
and g.FkPermissionId = 100
)
Or you could use a left join like this.
select g.GroupId
, 100
from [Group] g
left join GroupPermission gp on gp.FkGroupId = g.GroupId
and gp.FkPermissionId = 100
where g.GroupLevel = 0
and gp.FkGroupId is null

How to get a child table records which exist in results of a table valued function

I have a table named TBL_WorkOrder as below :
+----+------------+----------------+
| Id | SystemCode | WorkOrderTitle |
+----+------------+----------------+
| 1 | C001 | Title 1 |
| 2 | C002 | Title 2 |
| 3 | C003 | Title 3 |
+----+------------+----------------+
and another table named TBL_WorkGroup
+----+---------------+
| Id | WorkGroupName |
+----+---------------+
| 1 | WorkGroup1 |
| 2 | WorkGroup2 |
| 3 | WorkGroup3 |
+----+---------------+
Each work order can contain different work groups as below (TBL_WorkOrderGroup)
+----+-------------+-------------+
| Id | WorkOrderId | WorkGroupId |
+----+-------------+-------------+
| 1 | 1 | 1 |
| 2 | 1 | 3 |
| 3 | 2 | 1 |
+----+-------------+-------------+
The problem is that I send a varchar string like '1,3' to the stored procedure. This varchar is changed to a table using a table valued function. I want to obtain the work orders that contain both '1' and '3' as their work groups.
What should i do in this case?
DECLARE #String VARCHAR(100) = '1,3'
;WITH Split AS
(
SELECT SUBSTRING(#String,0,CHARINDEX(',',#String)) SplitStr,SUBSTRING(#String,CHARINDEX(',',#String)+1,LEN(#String)) RemainStr
UNION ALL
SELECT CASE WHEN CHARINDEX(',',RemainStr) = 0 THEN RemainStr ELSE SUBSTRING(RemainStr,0,CHARINDEX(',',RemainStr)) END,
CASE WHEN CHARINDEX(',',RemainStr) = 0 THEN '' ELSE SUBSTRING(RemainStr,CHARINDEX(',',RemainStr)+1,LEN(RemainStr)) END
FROM Split
WHERE ISNULL(RemainStr,'') <> ''
)
SELECT SplitStr FROM Split

Counting on multiple columns

I have a table like this:
+------------+---------------+-------------+
|store_number|entrance_number|camera_number|
+------------+---------------+-------------+
| 1 | 1 | 1 |
| 1 | 1 | 2 |
| 2 | 1 | 1 |
| 2 | 2 | 1 |
| 2 | 2 | 2 |
| 3 | 1 | 1 |
| 4 | 1 | 1 |
| 4 | 1 | 2 |
| 4 | 2 | 1 |
| 4 | 3 | 1 |
+------------+---------------+-------------+
In summary the stores are numbered 1 and up, the entrances are numbered 1 and up for each store, and the cameras are numbered 1 and up for each entrance.
What I want to do is count how many how many entrances in total, and how many cameras in total for each store. Producing this result from the above table:
+------------+---------------+-------------+
|store_number|entrances |cameras |
+------------+---------------+-------------+
| 1 | 1 | 2 |
| 2 | 2 | 3 |
| 3 | 1 | 1 |
| 4 | 3 | 4 |
+------------+---------------+-------------+
How can I count on multiple columns to produce this result?
You can do this with a GROUP BY and a COUNT() of each item:
Select Store_Number,
Count(Distinct Entrance_Number) as Entrances,
Count(Camera_Number) As Cameras
From YourTable
Group By Store_Number
From what I can tell from your expected output, you're looking for the number of cameras that appear, whilst also looking for the DISTINCT number of entrances.
This will work as well,
DECLARE #store TABLE
( store_number INT,entrance_number INT,camera_number INT)
INSERT INTO #store VALUES(1,1,1),(1,1,2),(2,1,1),(2,2,1),
(2,2,2),(3,1,1),(4,1,1),(4,1,2),(4,2,1),(4,3,1)
SELECT AA.s store_number, BB.e entrances,AA.c cameras FROM (
SELECT s,COUNT(DISTINCT c) c FROM ( SELECT store_number s,
CONVERT(VARCHAR,store_number) + CONVERT(VARCHAR,entrance_number) +
CONVERT(VARCHAR,camera_number) c FROM #store ) A GROUP BY s ) AA
LEFT JOIN
( SELECT s,COUNT(DISTINCT e) e FROM ( SELECT store_number s,
CONVERT(VARCHAR,store_number) + CONVERT(VARCHAR,entrance_number) e
FROM #store ) B GROUP BY s ) BB ON AA.s = BB.s
Hope it helped. :)

Check if relation exists and return true or false

I have 3 tables, Category Step and CategoryStep, where CategoryStep relates the two other tables together. I want to return all categories with a true/false column whether or not the relation exists in CategoryStep based on a StepID.
The schema for the tables is simple,
Category:
CategoryID | CategoryName
Step:
StepID | StepName
CategoryStep:
CategoryStepID | CategoryID | StepID
When trying to get results based on StepID, I only get the relations that exist, and not ones that don't.
SELECT [CategoryID], [Category], CAST(CASE WHEN [CategoryStep].[CategoryStep] IS NULL THEN 0 ELSE 1 END AS BIT) AS related
FROM Category
LEFT JOIN CategoryStep ON Category.CategoryID = CategoryStep.CategoryID
INNER JOIN Step ON CategoryStep.StepID = Step.StepID
WHERE Step.StepID = 2
Step Table:
|StepID | StepName
|-------|---------
| 1 | StepOne
| 2 | StepTwo
| 3 | StepThree
Category Table:
| CategoryID | CategoryName
|------------|-------------
| 1 | Holidays
| 2 | States
| 3 | Cities
| 4 | Animals
| 5 | Food
CategoryStep Table
| CategoryStepID | CategoryID | StepID
|----------------|------------|-------
| 1 | 1 | 1
| 2 | 1 | 2 <--
| 3 | 2 | 1
| 4 | 2 | 3
| 5 | 3 | 2 <--
| 6 | 4 | 1
| 7 | 4 | 2 <--
| 8 | 4 | 3
| 9 | 5 | 1
| 10 | 5 | 3
So, if I was looking for StepID = 2 the result table I am looking for is:
| CategoryID | Category | Related
|------------|----------|--------
| 1 | Holidays | 1
| 2 | States | 0
| 3 | Cities | 1
| 4 | Animals | 1
| 5 | Food | 0
Try replacing the INNER JOIN with a LEFT JOIN.
Update:
The fatal flaw with your original attempt was the WHERE clause. You were performing the correct LEFT JOIN, but the WHERE clause was filtering off category records which did not match. In the query below, I moved the check for step ID into the join condition, where it belongs.
SELECT [CategoryID], [Category],
CAST(CASE WHEN [CategoryStep].[CategoryStep] IS NULL THEN 0 ELSE 1 END AS BIT) AS related
FROM Category
LEFT JOIN CategoryStep
ON Category.CategoryID = CategoryStep.CategoryID AND
CategoryStep.StepCodeID = 2
LEFT JOIN Step
ON CategoryStep.StepID = Step.StepID

SQL: sorting child rows under parent row

I have this table in my SQL Server database.
MenuID MenuText ParentMenu MenuOrder MenuLevel
-------------------------------------------------------------
1 Home 0 1 0
2 Administrator 0 2 0
3 Groups 2 1 1
4 Users 2 2 1
5 Permissions 2 3 1
6 Test Level2 3 1 2
7 Test Level3 6 1 3
I want to sort this table rows like this:
Home, Administrator are MenuLevel 0 items.
MenuLevel 1 items will be under its top level menus according to their ParentMenu column which points to the parent MenuID. The child items will be sorted according to their MenuOrder column.
I tried so many things, but couldn't get the idea how it will be done using query.
Try this one:
SQL Fiddle
;WITH Cte AS(
SELECT *,
DisplayOrder = CAST(ROW_NUMBER() OVER(PARTITION BY ParentMenu ORDER BY MenuOrder) AS VARCHAR(MAX))
FROM Test
WHERE
ParentMenu = 0
UNION ALL
SELECT
t.MenuID,
t.MenuText,
t.ParentMenu,
t.MenuOrder,
t.MenuLevel,
DisplayOrder = c.DisplayOrder + CAST(ROW_NUMBER() OVER(PARTITION BY t.ParentMenu ORDER BY t.MenuOrder) AS VARCHAR(MAX))
FROM Cte c
INNER JOIN Test t
ON c.MenuID = t.ParentMenu
)
SELECT
MenuID,
MenuText,
ParentMenu,
MenuOrder,
MenuLevel
FROM cte
ORDER BY DisplayOrder
Result:
| MenuID | MenuText | ParentMenu | MenuOrder | MenuLevel |
|--------|---------------|------------|-----------|-----------|
| 1 | Home | 0 | 1 | 0 |
| 2 | Administrator | 0 | 2 | 0 |
| 3 | Groups | 2 | 1 | 1 |
| 6 | Test Level2 | 3 | 1 | 2 |
| 7 | Test Level3 | 6 | 1 | 3 |
| 4 | Users | 2 | 2 | 1 |
| 5 | Permissions | 2 | 3 | 1 |