select multiple count set, sql server 2008 r2 - sql
Using SQL Server 2008 R2, i have following result set returned by a query -
QID QcID QtID QsID
21 1 SC 3
4 1 SC 1
8 1 MC 1
2 1 SC 1
23 1 SC 3
24 1 SC 3
5 1 SC 1
22 1 SC 3
1 1 SC 1
29 1 MC 3
10 1 MC 1
30 1 MC 3
26 1 MC 3
25 1 SC 3
6 1 MC 1
27 1 MC 3
7 1 MC 1
3 1 SC 1
28 1 MC 3
9 1 MC 1
Now i want to find a random set of 15 QID, which must includes say -
9 QsID having QsID = 1
6 QsID having QsID = 3
9 QtID having QtID = SC
6 QtID having QtID = MC
15 QsID having QtID = 1
how it can be done keeping performance in mind as it may have tens of thousand records.
# Damien_The_Unbeliever the expected output could be -
21 1 SC 3
4 1 SC 1
8 1 MC 1
2 1 SC 1
23 1 SC 3
24 1 SC 3
5 1 SC 1
1 1 SC 1
10 1 MC 1
25 1 SC 3
6 1 MC 1
27 1 MC 3
7 1 MC 1
3 1 SC 1
28 1 MC 3
Also forget the random, how it be possible to select the set satisfying all the conditions.
EDIT2:
Well, how about using a stored procedure for that?
Assumption is that you have 4 sets of conditions you sample data with. Deduced from the output you provided. It might not be right but then again you can adjust it as you like.
Parameters:
#SIZE - is the size of sampling result set in rows
#P1-#P3 - percent of the sampling result set that should be filled with random rows for particular set of conditions.
#P4=#SIZE-(#N1+#N2+#N3)
CREATE PROCEDURE sqlsampling
#SIZE INT, #P1 DECIMAL(6,4), #P2 DECIMAL(6,4), #P3 DECIMAL(6,4)
AS
DECLARE #N1 INT, #N2 INT, #N3 INT, #N4 INT;
SET #N1=CEILING(#SIZE*#P1*0.01);
SET #N2=CEILING(#SIZE*#P2*0.01);
SET #N3=CEILING(#SIZE*#P3*0.01);
SET #N4=#SIZE-(#N1+#N2+#N3);
CREATE TABLE #sample(QID INT, QcID INT, QtID CHAR(2), QsID INT);
INSERT INTO #sample
SELECT TOP(#N1) * FROM mytable
WHERE QtID = 'MC' AND QsID = 1
ORDER BY CHECKSUM(NEWID());
INSERT INTO #sample
SELECT TOP(#N2) * FROM mytable
WHERE QtID = 'MC' AND QsID = 3 AND QID NOT IN(SELECT QID FROM #sample)
ORDER BY CHECKSUM(NEWID());
INSERT INTO #sample
SELECT TOP(#N3) * FROM mytable
WHERE QtID = 'SC' AND QsID = 1 AND QID NOT IN(SELECT QID FROM #sample)
ORDER BY CHECKSUM(NEWID());
INSERT INTO #sample
SELECT TOP(#N4) * FROM mytable
WHERE QtID = 'SC' AND QsID = 3 AND QID NOT IN(SELECT QID FROM #sample)
ORDER BY CHECKSUM(NEWID());
SELECT * FROM #sample;
DROP TABLE #sample;
GO
If we execute it on your sample data like this
EXEC sqlsampling #SIZE=15, #P1=26.666, #P2=13.333, #P3=33.333;
It will give us the output:
QID QCID QTID QSID
10 1 MC 1
9 1 MC 1
7 1 MC 1
6 1 MC 1
27 1 MC 3
30 1 MC 3
1 1 SC 1
4 1 SC 1
3 1 SC 1
5 1 SC 1
2 1 SC 1
21 1 SC 3
23 1 SC 3
25 1 SC 3
24 1 SC 3
Other considerations:
Correct indexes for your sets of conditions should help
CHECKSUM(NEWID()) helps us a bit with the penalty of using NEWID()
Original answer:
You can do something like this:
SELECT TOP 15 * FROM
(
SELECT * FROM (SELECT TOP 9 QID FROM mytable
WHERE QsID = 1
ORDER BY CHECKSUM(NEWID())) a
UNION
SELECT * FROM (SELECT TOP 6 QID FROM mytable
WHERE QsID = 3
ORDER BY CHECKSUM(NEWID())) b
...
) z ORDER BY CHECKSUM(NEWID())
Perhaps you may try percent with top.. this is not the complete answer, but to throw some light into the direction..
select * from demo where qid in
(select top 40 percent qid
from demo order by newid())
;
Here is also a Reference to tablesample: http://msdn.microsoft.com/en-us/library/ms189108.aspx
Related
SQL: subset data: select id when time_id for id satisfy a condition from another column
I have a data (dt) in SQL like the following: ID time_id act rd 11 1 1 1 11 2 4 1 11 3 7 0 12 1 8 1 12 2 2 0 12 3 4 1 12 4 3 1 12 5 4 1 13 1 4 1 13 2 1 0 15 1 3 1 16 1 8 0 16 2 8 0 16 3 8 0 16 4 8 0 16 5 8 0 and I want to take the subset of this data such that only ids (and their corresponding time_id, act, rd) that has time_id == 5 is retained. The desired output is the following ID time_id act rd 12 1 8 1 12 2 2 0 12 3 4 1 12 4 3 1 12 5 4 1 16 1 8 0 16 2 8 0 16 3 8 0 16 4 8 0 16 5 8 0 I know I should use having clause somehow but have not been successful so far (returns me empty outputs). below is my attempt: SELECT * FROM dt GROUP BY ID Having min(time_id) == 5;
This query: select id from tablename where time_id = 5 returns all the ids that you want in the results. Use it with the operator IN: select * from tablename where id in (select id from tablename where time_id = 5)
You can use a correlated subquery with exists: select t.* from t where exists (select 1 from t t2 where t2.id = t.id and t2.time_id = 5);
WITH temp AS ( SELECT id FROM tab WHERE time_id = 5 ) SELECT * FROM tab t join temp tp on(t.id=tp.id);
check this query select * from table t1 join (select distinct ID from table t where time_id = 5) t2 on t1.id =t2.id;
how to reset the column value
i have table with 9 records that 2 records with _id = 1 was deleted: id | name | index | _id 1 a 1 1 8 b 3 1 9 c 7 1 10 d 4 1 15 e 2 1 16 d 1 2 17 e 2 2 and I want to reset the index of _id = 1 like this: id | name | index | _id 1 a 1 1 8 b 2 1 9 c 3 1 10 d 4 1 15 e 5 1 16 d 1 2 17 e 2 2 i 'd use this query declare #_idCount int = (select count(*) from tbl where _id = 1), #index int = 1 while(#_idCount > 0) begin update tbl set code = #index where _id = 1 set #index = #index + 1 set #picCount = #picCount - 1 end but this code is set all of record with same code. what can i do to solve it?
You can simply use ROW_NUMBER: WITH CTE AS ( SELECT id, name, [index], [_id], new_index = ROW_NUMBER() OVER(PARTITION BY [_id] ORDER BY [id]) FROM dbo.tbl ) UPDATE CTE SET [index] = new_index;
SQL Recursive CTE unexpectedly returns alternating sets
I am trying to get the use recursive CTE to repeat the same pattern over and over, resetting when "Scenario" increases in value. RowNumber repeats 1-21 (as desired), but whenever "Scenario" is an even number, there are too few items in the "Vals" column to feed into "Value". I can't figure out which part of the code is causing me to be 1 short for only even Scenarios. Below are the results of the code I'm using at the bottom. Scenario RowNumber Value Vals 1 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 4 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 5 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 6 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 7 A A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 8 A A,A,A,A,A,A,A,A,A,A,A,B,C 1 9 A A,A,A,A,A,A,A,A,A,A,B,C 1 10 A A,A,A,A,A,A,A,A,A,B,C 1 11 A A,A,A,A,A,A,A,A,B,C 1 12 A A,A,A,A,A,A,A,B,C 1 13 A A,A,A,A,A,A,B,C 1 14 A A,A,A,A,A,B,C 1 15 A A,A,A,A,B,C 1 16 A A,A,A,B,C 1 17 A A,A,B,C 1 18 A A,B,C 1 19 A B,C 1 20 B C 1 21 C 2 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 4 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 5 A A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 6 A A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 7 A A,A,A,A,A,A,A,A,A,A,B,B,C 2 8 A A,A,A,A,A,A,A,A,A,B,B,C 2 9 A A,A,A,A,A,A,A,A,B,B,C 2 10 A A,A,A,A,A,A,A,B,B,C 2 11 A A,A,A,A,A,A,B,B,C 2 12 A A,A,A,A,A,B,B,C 2 13 A A,A,A,A,B,B,C 2 14 A A,A,A,B,B,C 2 15 A A,A,B,B,C 2 16 A A,B,B,C 2 17 A B,B,C 2 18 B B,C 2 19 B C 2 20 C 2 21 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 3 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 4 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 5 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 6 A A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 7 A A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 8 A A,A,A,A,A,A,A,A,A,A,B,C,C 3 9 A A,A,A,A,A,A,A,A,A,B,C,C 3 10 A A,A,A,A,A,A,A,A,B,C,C 3 11 A A,A,A,A,A,A,A,B,C,C 3 12 A A,A,A,A,A,A,B,C,C 3 13 A A,A,A,A,A,B,C,C 3 14 A A,A,A,A,B,C,C 3 15 A A,A,A,B,C,C 3 16 A A,A,B,C,C 3 17 A A,B,C,C 3 18 A B,C,C 3 19 B C,C 3 20 C C 3 21 C 4 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 4 A A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 5 A A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 6 A A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 7 A A,A,A,A,A,A,A,A,A,B,B,B,C 4 8 A A,A,A,A,A,A,A,A,B,B,B,C 4 9 A A,A,A,A,A,A,A,B,B,B,C 4 10 A A,A,A,A,A,A,B,B,B,C 4 11 A A,A,A,A,A,B,B,B,C 4 12 A A,A,A,A,B,B,B,C 4 13 A A,A,A,B,B,B,C 4 14 A A,A,B,B,B,C 4 15 A A,B,B,B,C 4 16 A B,B,B,C 4 17 B B,B,C 4 18 B B,C 4 19 B C 4 20 C This is the code I used to generate the above sample. Where am I going wrong? CREATE TABLE #temp3 ( Scenario INT ,Vals VARCHAR(64) ,LEN INT ) ; WITH vals AS ( SELECT v.* FROM (VALUES ('A'), ('B'), ('C')) v(x) ), CTE AS ( SELECT CAST('A' AS VARCHAR(MAX)) AS STR, 0 AS LEN UNION ALL SELECT (CTE.STR + ',' + vals.x), CTE.LEN + 1 FROM CTE JOIN vals ON vals.x >= RIGHT(CTE.STR, 1) WHERE CTE.LEN < 19 ) INSERT INTO #temp3 SELECT ROW_NUMBER() OVER(ORDER BY STR + ',C') AS Scenario ,STR + ',C' AS Vals ,LEN FROM CTE WHERE STR + 'C' LIKE '%B%' AND LEN = 19 ; -- Split strings created above into individual characters WITH cte(Scenario, Value, Vals) AS ( SELECT Scenario ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) AS Value ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') AS Vals FROM #temp3 UNION ALL SELECT Scenario ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') FROM cte WHERE Vals > '' ) SELECT Scenario ,ROW_NUMBER() OVER (PARTITION BY Scenario ORDER BY Scenario) RowNumber ,Value ,Vals FROM cte t
I'm not exactly sure what the problem you are describing is, but the ROW_NUMBER() should use an ORDER BY clause that completely orders the rows in each partition. When you use "PARTITION BY Scenario ORDER BY Scenario" the order in which the ROW_NUMBER() values are assigned is undefined. Try something like WITH cte(Scenario, depth, Value, Vals) AS ( SELECT Scenario, 0 depth ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) AS Value ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') AS Vals FROM #temp3 UNION ALL SELECT Scenario, depth+1 ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') FROM cte WHERE Vals > '' ) SELECT Scenario ,depth ,ROW_NUMBER() OVER (PARTITION BY Scenario ORDER BY depth ) RowNumber ,Value ,Vals FROM cte t
SQL recursive hierarchy
I am struggling to get one recursive CTE to work as desired but still with no chance.. So, I have the following similar table structures: tblMapping: map_id | type_id | name | parent_id 1 1 A1 0 2 1 A2 0 3 1 A3 1 4 1 A4 3 5 2 B1 0 6 2 B2 5 7 2 B3 6 8 1 A5 4 9 2 B4 0 tblRoleGroup: role_group_id | type_id | map_id | desc_id 1 1 0 null 1 2 0 null 2 1 3 1 2 2 6 0 3 1 8 1 3 2 9 1 In tblRoleGroup, the desc_id field means: null - allow all (used only in combination with map_id=0) 0 - allow all from parent including parent 1 - allow only current node Still in tblRoleGroup if map_id=0 then the query should get all elements from same type_id The query result should look like this: role_group_id | type_id | map_id | path 1 1 1 A1 1 1 2 A2 1 1 3 A1.A3 1 1 4 A1.A3.A4 1 1 8 A1.A3.A4.A5 1 2 5 B1 1 2 6 B1.B2 1 2 7 B1.B2.B3 1 2 9 B4 2 1 3 A1.A3 2 2 6 B1.B2 2 2 7 B1.B2.B3 3 1 8 A1.A3.A4.A5 3 2 9 B4 The query below solves only a part of the expected result, but I wasn't able to make it work as the expected result.. WITH Hierarchy(map_id, type_id, name, Path) AS ( SELECT t.map_id, t.type_id, t.name, CAST(t.name AS varchar(MAX)) AS Expr1 FROM dbo.tblMapping AS t LEFT JOIN dbo.tblMapping AS t1 ON t1.map_id = t.parent_id WHERE (t1.parent_id=0) UNION ALL SELECT t.map_id, t.type_id, t.name, CAST(h.Path + '.' + t.name AS varchar(MAX)) AS Expr1 FROM Hierarchy AS h JOIN dbo.tblMapping AS t ON t.parent_id = h.map_id ) SELECT h.map_id, h.type_id, t.role_group_id, h.Path AS Path FROM Hierarchy AS h LEFT JOIN dbo.tblRoleGroup t ON t.map_id = h.map_id Could someone help me on this? Thank you
At first I create a function that brings all descendants of passed map_id: CREATE FUNCTION mapping (#map_id int) RETURNS TABLE AS RETURN ( WITH rec AS ( SELECT map_id, [type_id], CAST(name as nvarchar(max)) as name, parent_id FROM tblMapping WHERE map_id = #map_id UNION ALL SELECT m.map_id, m.[type_id], r.name+'.'+m.name, m.parent_id FROM rec r INNER JOIN tblMapping m ON m.parent_id = r.map_id ) SELECT * FROM rec ); GO Then run this: ;WITH rec AS ( SELECT map_id, [type_id], CAST(name as nvarchar(max)) as name, parent_id FROM tblMapping WHERE parent_id=0 UNION ALL SELECT m.map_id, m.[type_id], r.name+'.'+m.name, m.parent_id FROM rec r INNER JOIN tblMapping m ON m.parent_id = r.map_id ) SELECT t.role_group_id, r.[type_id], r.map_id, r.name as [path] FROM tblRoleGroup t CROSS JOIN rec r WHERE r.[type_id] = CASE WHEN t.desc_id IS NULL AND t.map_id = 0 THEN t.[type_id] ELSE NULL END OR r.map_id = CASE WHEN t.desc_id = 1 THEN t.map_id ELSE NULL END OR r.map_id IN ( SELECT map_id FROM dbo.mapping (CASE WHEN t.desc_id = 0 THEN t.map_id ELSE NULL END) ) ORDER BY role_group_id, r.[type_id], r.map_id Will give you: role_group_id type_id map_id path 1 1 1 A1 1 1 2 A2 1 1 3 A1.A3 1 1 4 A1.A3.A4 1 1 8 A1.A3.A4.A5 1 2 5 B1 1 2 6 B1.B2 1 2 7 B1.B2.B3 1 2 9 B4 2 1 3 A1.A3 2 2 6 B1.B2 2 2 7 B1.B2.B3 3 1 8 A1.A3.A4.A5 3 2 9 B4
T-SQL Reverse Pivot on every character of a string
We have a table like below in an sql server 2005 db: event_id staff_id weeks 1 1 NNNYYYYNNYYY 1 2 YYYNNNYYYNNN 2 1 YYYYYYYYNYYY This is from a piece of timetabling software and is basically saying which staff members are assigned to an event (register) and the set of weeks they are teaching that register. So staff_id 1 isn't teaching the first 3 weeks of event 1 but is teaching the following 4.... Is there an easy way to convert that to an easier form such as: event_id staff_id week 1 1 4 1 1 5 1 1 6 1 1 7 1 1 10 1 1 11 1 1 12 1 2 1 1 2 2 1 2 3 1 2 7 1 2 8 1 2 9 2 1 1 2 1 2 2 1 3 2 1 4 2 1 5 2 1 6 2 1 7 2 1 8 2 1 10 2 1 11 2 1 12
WITH cte AS ( SELECT 1 AS [week] UNION ALL SELECT [week] + 1 FROM cte WHERE [week] < 53 ) SELECT t.event_id, t.staff_id, cte.[week] FROM your_table AS t INNER JOIN cte ON LEN(ISNULL(t.weeks, '')) >= cte.[week] AND SUBSTRING(t.weeks, cte.[week], 1) = 'Y' ORDER BY t.event_id, t.staff_id, cte.[week]