In my MVC 4 application I was looking for optgroup for dropdownlist and found this very helpful.
I followed the steps and achieved that as well but currently I am facing some issues.My controller code looks like:
Model.ddlProject = db.Projects.OrderBy(t => t.Type)
.Select(t => new GroupedSelectListItem
{
GroupName = t.Type,
Text = t.Name,
Value = SqlFunctions.StringConvert((decimal)t.Id)
});
The grouping is done here but I want it in a different manner.With this I am able to bind the dropdown as shown below:
Now let me tell about my table structure.I have one table with following structure:
Here I have one hierarchy such that Customer -> Client -> Projects . Thus, I need to group by Clients such that all the projects should be listed under the clients.I want something like this:
Hence I have been stuck with query over here,the query to achieve this.I need to show all the client names in the group name and for clients I need to list all the respective projects.I guess I am clear with my requirement.Kind of got stuck here so any help would be great.Thanks in advance.
As Stephen Muecke said in the comment section that Projects and Clients are 2 different things. You should have a Client table and a separate Project table containing a column with foreign key to the Client table. So below solution is according to your existing table structure.
Dummy Schema
DECLARE #clientprj TABLE ([id] int identity(1,1), [name] varchar(30), Desc1 varchar(30), ParentId int, pType varchar(30));
INSERT #clientprj ([name], Desc1, ParentId, pType) VALUES ('client1', '', 0, 'clt'), ('prj1', '', 1, 'prj'), ('prj2', '', 1, 'prj'), ('client2', '', 0, 'clt'), ('prj n', '', 4, 'prj')
and Here is the query
SELECT GroupName, GroupKey, ProjName, ProjId
FROM
(
(
SELECT NAME AS GroupName
,Id AS GroupKey
FROM #clientprj m
WHERE ParentId = 0
) m
FULL OUTER JOIN
(
SELECT NAME AS ProjName
,Id AS ProjId
,ParentId
FROM #clientprj
)
t ON m.GroupKey = t.ParentId
)
WHERE ParentId <> 0
Which return the following output.
GroupName GroupKey ProjName ProjId
client1 1 prj1 2
client1 1 prj2 3
client2 4 prj n 5
and your controller method which calls this query like this -
Model.ddlProject = db.NewMethod
.Select(t => new GroupedSelectListItem
{
GroupName = t.GroupName,
GroupKey = t.GroupKey.ToString(),
Text = t.ProjName,
Value = t.ProjId.ToString()
});
and then bind your dropdownlist. Best of luck...
Related
hello first off sorry for bad explain but ill try my best
so im having 2 table
table 1 = sb_admins and
has COLUMNS =
1. aid (AUTO_INCREMENT)
2. user
3. auth
4. passoword
5. gid
6. email
table 2 = sb_admins_servers_groups and
has COLUMNS =
1. admin_id
2. group_id
3. srv_group_id
4. server_id
I need to get values from aid to admin_id with a INSERT INTO
what i have try but failed
INSERT INTO sb_admins_servers_groups (admin_id, group_id, srv_group_id, server_id)
SELECT aid FROM sb_admins
INSERT
INTO sb_admins_servers_groups (
admin_id,
group_id,
srv_group_id,
server_id
)
VALUES (
(
SELECT aid
FROM sb_admins
WHERE authid = '{steamid}'
),
'1',
'1',
'-1'
)
I am trying to order values that are going to be inserted into another table based on their order value from a secondary table. We are migrating old data to a new table with a slightly different structure.
I thought I would be able to accomplish this by using the string_split function but I'm not very skilled with SQL and so I am running into some issues.
Here is what I have:
UPDATE lse
SET Options = a.Options
FROM
dbo.LessonStepElement as lse
CROSS JOIN
(
SELECT
tbl1.*
tbl2.Options,
tbl2.QuestionId
FROM
dbo.TrainingQuestionAnswer as tbl1
JOIN (
SELECT
string_agg((CASE
WHEN tqa.CorrectAnswer = 1 THEN REPLACE(tqa.AnswerText, tqa.AnswerText, '*' + tqa.AnswerText)
ELSE tqa.AnswerText
END),
char(10)) as Options,
tq.Id as QuestionId
FROM
dbo.TrainingQuestionAnswer as tqa
INNER JOIN
dbo.TrainingQuestion as tq
on tq.Id = tqa.TrainingQuestionId
INNER JOIN
dbo.Training as t
on t.Id = tq.TrainingId
WHERE
t.IsDeleted = 0
and tq.IsDeleted = 0
and tqa.IsDeleted = 0
GROUP BY
tq.Id,
tqa.AnswerDisplayOrder
ORDER BY
(SELECT [Value] FROM STRING_SPLIT((SELECT AnswerDisplayOrder FROM dbo.TrainingQuestion WHERE Id = tmq.Id), ','))
) as tbl2
on tbl1.TrainingQuestionId = tbl2.QuestionId
) a
WHERE
a.TrainingQuestionId = lse.TrainingQuestionId
The AnswerDisplayOrder that I am using is just a nvarchar comma separated list of the ids for the answers to the question.
Here is an example:
I have 3 rows in the TrainingQuestionAnswer table that look like the following.
ID TrainingQuestionId AnswerText
-------------------------------------------
215 100 No
218 100 Yes
220 100 I'm not sure
I have 1 row in the TrainingQuestion table that looks like the following.
ID AnswerDisplayOrder
--------------------------
100 "218,215,220"
Now what I am trying to do is when I update the row in the new table with all of the answers combined, the answers will need to be in the correct order which is dependent on the AnswerDisplayOrder in the TrainingQuestion table. So in essence, the new table would have a row that would look similar to the following.
ID Options
--------------
193 "Yes No I'm not sure"
I'm aware that the way I'm trying to do it might not be even possible at all. I am still learning and would just love some advice or guidance on how to make this work. I also know that string_split does not guarantee order. I'm open to other suggestions that do guarantee the order as well.
I simplified the issue in the question to the following approach, that is a possible solution to your problem. If you want to get the results from the question, you need a splitter, that returns the substrings and the positions of the substrings. STRING_SPLIT() is available from SQL Server 2016, but is not an option here, because (as is mentioned in the documentation) the output rows might be in any order and the order is not guaranteed to match the order of the substrings in the input string.
But you may try to use a JSON based approach, with a small string manipulation, that transforms answers IDs into a valid JSON array (218,215,220 into [218,215,220]). After that you can easily parse this JSON array with OPENJSON() and default schema. The result is a table, with columns key, value and type and the key column (again from the documentation) holds the index of the element in the specified array.
Tables:
CREATE TABLE TrainingQuestionId (
ID int,
TrainingQuestionId int,
AnswerText varchar(1000)
)
INSERT INTO TrainingQuestionId
(ID, TrainingQuestionId, AnswerText)
VALUES
(215, 100, 'No'),
(218, 100, 'Yes'),
(220, 100, 'I''m not sure')
CREATE TABLE TrainingQuestion (
ID int,
AnswerDisplayOrder varchar(1000)
)
INSERT INTO TrainingQuestion
(ID, AnswerDisplayOrder)
VALUES
(100, '218,215,220')
Statement:
SELECT tq.ID, oa.Options
FROM TrainingQuestion tq
OUTER APPLY (
SELECT STRING_AGG(tqi.AnswerText, ' ') WITHIN GROUP (ORDER BY CONVERT(int, j.[key])) AS Options
FROM OPENJSON(CONCAT('[', tq.AnswerDisplayOrder, ']')) j
LEFT JOIN TrainingQuestionId tqi ON TRY_CONVERT(int, j.[value]) = tqi.ID
) oa
Result:
ID Options
100 Yes No I'm not sure
Notes: You need SQL Server 2017+ to use STRING_AGG(). For SQL Server 2016 you need a FOR XML to aggregate strings.
declare #TrainingQuestionAnswer table
(
ID int,
TrainingQuestionId int,
AnswerText varchar(20)
);
insert into #TrainingQuestionAnswer(ID, TrainingQuestionId, AnswerText)
values(215, 100, 'No'), (218, 100, 'Yes'), (220, 100, 'I''m not sure');
declare #TrainingQuestiontest table
(
testid int identity,
QuestionId int,
AnswerDisplayOrder varchar(200)
);
insert into #TrainingQuestiontest(QuestionId, AnswerDisplayOrder)
values(100, '218,215,220'), (100, '220,218,215'), (100, '215,218');
select *,
(
select string_agg(pci.AnswerText, '==') WITHIN GROUP ( ORDER BY pci.pos)
from
(
select a.AnswerText,
pos = charindex(concat(',', a.ID, ','), concat(',', q.AnswerDisplayOrder,','))
from #TrainingQuestionAnswer as a
where a.TrainingQuestionId = q.QuestionId
and charindex(concat(',', a.ID, ','), concat(',', q.AnswerDisplayOrder,',')) >= 1
) as pci
) as TestAnswerText
from #TrainingQuestiontest as q;
I have a table pulling userid's and their personal and work e-mails. I'd like to have one line per id showing both types of e-mails, but I can't figure out how to do that.
declare #t table(NPI int, email varchar(50), emailtype varchar(50))
insert into #t
values(1, 'john#home', 'personal'), (1, 'john#work', 'work');
This is the query I've written so far, which puts this on 2 separate rows:
select npi, case when emailtype = 'personal' then email end as personalemail,
case when emailtype = 'work' then email end as workemail
from #t;
Current Output:
npi personalemail workemail
1 john#home NULL
1 NULL john#work
What I'd like to see is:
npi personalemail workemail
1 john#home john#work
How can I do this?
This has been asked and answered around here about a million times. It is called conditional aggregation or crosstab. It is faster to write an answer than find one. As an alternative you could use PIVOT but I find the syntax a bit obtuse for me.
select NPI
, max(case when emailtype = 'personal' then email end) as PersonalEmail
, max(case when emailtype = 'work' then email end) as WorkEmail
from #t
group by NPI
Use pivot
SELECT
*
FROM #T
PIVOT
(
MAX(email)
FOR EmailType IN
(
personal,work
)
)Q
I need to model groups of persons and I can't find a way to design tabels to do it efficiently.
Groups can be thought as sets, unordered collections of one or more persons, each group should be uniquely identified by its components.
Edit: and a person can be part of more than one group.
My first attempt looks like this.
A table which contains all "persons" managed by the system.
table Persons(
id int,
name varchar,
(other data...)
)
a table that contains groups and all group properties:
table Groups(
group_id int,
group_name varchar,
(other data...)
)
and a table with the association between persons and groups
table gropus_persons (
person_id int,
group_id in
)
This design doesn't fit well with this requirements because it is hard to write the query to retrieve the group id from a list of components.
The only query I could come up to find the group composed by persons (1, 2, 3) looks like this:
select *
from groups g
where
g.group_id in (select group_id from gropus_persons where person_id = 1)
and g.group_id in (select group_id from gropus_persons where person_id = 2)
and g.group_id in (select group_id from gropus_persons where person_id = 3)
and not exists (select 1 from gropus_persons where group_id = g.group_id and person_id not in (1,2,3))
the problem is that the number of components is variable so I can only use a dynamically generated query and add a subquery for each component each time I need to find a new group.
Is there a better solution?
Thank you in advice for the help!
You need to group by the "group" and count how many hits you receive. For this, you only need the intersection table:
select GroupID, count(*) as MemberCount
from GroupsPersons
where PersonID in( 1, 2, 3 )
group by GroupID
having count(*) = 3;
The problem comes with making this query suitable for a varying list of person id values. As you seem to already realize this will require dynamic SQL, the pseudo-code will look something like this:
stmt := 'select GroupID, count(*) as MemberCount '
|| 'from GroupsPersons '
|| 'where PersonID in( ' || CSVList || ' ) '
|| 'group by GroupID '
|| 'having count(*) = ' || length( CSVList );
The one potential bug you have to be wary of is if the same id repeats in the list. For example: CSVList := '1, 2, 3, 2';
This will generate a correct count(*) value of 3, but the having clause will be looking for 4.
Another solution to consider is to pivot/xpath the set of person IDs in alpha sequence and store it in your groups table and compare that string with your target.
For your example, you'd use Select group_id from groups where personIDs = '1,2,3,'
How about this, I think the schema is the same as yours, not sure:
create table Groups(
group_id int primary key,
group_name varchar(100)
);
create table Persons(
person_id int primary key,
name varchar
);
create table Membership(
group_id int REFERENCES Groups (group_id),
person_id int REFERENCES Persons (person_id)
);
INSERT INTO Persons
VALUES (1, 'p1'),
(2, 'p2'),
(3, 'p2'),
(4, 'p2');
INSERT INTO Groups
VALUES (1, 'group1'),
(2, 'group2');
INSERT INTO Membership
VALUES (1, 1),
(1, 2),
(2, 2),
(1, 3);
Then select:
select p.name, g.group_name
from Persons as p
join Membership as m on p.person_id = m.person_id
join Groups as g on g.group_id = m.group_id
where m.group_id in (1, 2);
Obviously data would need to be adjusted to suit yours.
Recently I been working on project, where need to populated Dim Tables from EDW Tables.
EDW Tables are of type II which does maintain historical data. When comes to load Dim Table, for which source may be multiple EDW Tables or would be single table with multi level pivoting (on attributes).
Mean: There would be 10 records - one for each attribute which need to be pivoted on domain_code to make a single row in Dim. Out of these 10 records there would be some attributes with same domain_code but with different sub_domain_code, which needs further pivoting on subdomain code.
Ex:
if i got domain code: 01,02, 03 => which are straight pivot on domain code
I would also have domain code: 10 with subdomain code / version as 2006,2007,2008,2009
That means I need to split my source table with above attributes into two => one for domain code and other for domain_code + version.
so far so good.
When it comes to load Dim Table:
As per design specs for Dimensions (originally written by third party), what they want is:
for every single change in EDW (attribute), it should assemble all the related records (for that NK) mean new one with other attribute values which are current => process them to create a new dim record and insert it.
That mean if a single extract contains 100 records updated (one for each NK), it should assemble 100 + (100*9) records to insert / update dim table. How good is this approach.
Other way I tried to do is just do a lookup into dim table for that NK get the value's of recent records (attributes which not changed) and insert it and update the current one.
What would be the better approach assembling records at source side for one attribute change or looking into dim table's recent record and process it.
If this doesn't make sense, would like to elaborate it further.
Thanks
Here is the model of the tables
alt text http://img96.imageshack.us/img96/1203/modelzp.jpg
Have a look at this example.
It should be relatively straightforward.
It pivots the base data according to your rules.
It determines the change times for the denormalized "row"
It creates a triangular join to determine the start and end of each period (what I'm calling a snapshot)
Then it joins those windows to the base data to determine what the state of the data was at that time (the pivot is actually completed at this time)
I think you may need to look at the windowing mechanism - it's returning the right data, but I don't like the way the window overlap logic looks to me - it doesn't quite small right - I'm worried about the boundary conditions.
-- SO3014289
CREATE TABLE #src (
key1 varchar(4) NOT NULL
,key2 varchar(3) NOT NULL
,key3 varchar(3) NOT NULL
,AttribCode int NOT NULL
,AttribSubCode varchar(2)
,Value varchar(10) NOT NULL
,[Start] date NOT NULL
,[End] date NOT NULL
)
INSERT INTO #src VALUES
('9750', 'C04', '789', 1, NULL, 'AAA', '1/1/2000', '12/31/9999')
,('9750', 'C04', '789', 2, NULL, 'BBB', '1/1/2000', '12/31/9999')
,('9750', 'C04', '789', 3, 'V1', 'XXXX', '1/1/2000', '12/31/9999')
,('9750', 'C04', '789', 3, 'V2', 'YYYY', '1/1/2000', '1/2/2000')
,('9750', 'C04', '789', 3, 'V2', 'YYYYY', '1/2/2000', '12/31/9999')
;WITH basedata AS (
SELECT key1 + '-' + key2 + '-' + key3 AS NK
,CASE WHEN AttribCode = 1 THEN Value ELSE NULL END AS COL1
,CASE WHEN AttribCode = 2 THEN Value ELSE NULL END AS COL2
,CASE WHEN AttribCode = 3 AND AttribSubCode = 'V1' THEN Value ELSE NULL END AS COL3
,CASE WHEN AttribCode = 3 AND AttribSubCode = 'V2' THEN Value ELSE NULL END AS COL4
,[Start]
,[End]
FROM #src
)
,ChangeTimes AS (
SELECT NK, [Start] AS Dt
FROM basedata
UNION
SELECT NK, [End] AS Dt
FROM basedata
)
,Snapshots as (
SELECT s.NK, s.Dt AS [Start], MIN(e.Dt) AS [End]
FROM ChangeTimes AS s
INNER JOIN ChangeTimes AS e
ON e.NK = s.NK
AND e.Dt > s.Dt
GROUP BY s.NK, s.Dt
)
SELECT Snapshots.NK
,MAX(COL1) AS COL1
,MAX(COL2) AS COL2
,MAX(COL3) AS COL3
,MAX(COL4) AS COL4
,Snapshots.[Start]
,Snapshots.[End]
FROM Snapshots
INNER JOIN basedata
ON basedata.NK = Snapshots.NK
AND NOT (basedata.[End] <= Snapshots.[Start] OR basedata.[Start] >= Snapshots.[End])
GROUP BY Snapshots.NK
,Snapshots.[Start]
,Snapshots.[End]