Problem with DISTINCT and Linq2SQL - asp.net-mvc

I have a table like this:
idinterpretation | iddictionary | idword | meaning
1 1 1115 hello
2 1 1115 hi
3 1 1115 hi, bro
5 1 1118 good bye
6 1 1118 bye-bye
7 2 1119 yes
8 2 1119 yeah
9 2 1119 all rigth
And i try to get distinct rows (DISTINCT idword). So, at first i tried:
return dc.interpretations.Where(i => i.iddictionary == iddict).
ToList<interpretation>().Distinct(new WordsInDictionaryDistinct()).
OrderBy(w => w.word.word1).Skip(iSkip).Take(iTake);
But i have about 300.000 rows in my table and it is wrong solution.
Then, i tried:
IEnumerable<interpretation> res = (from interp in dc.interpretations
group interp by interp.idword into groupedres
select new interpretation
{
idword = groupedres.Key,
idinterpretation = groupedres.SingleOrDefault(i => i.idword == groupedres.Key).idinterpretation,
interpretation1 = groupedres.SingleOrDefault(i => i.idword == groupedres.Key).interpretation1,
iddictionary = groupedres.SingleOrDefault(i => i.idword == groupedres.Key).iddictionary
}).Skip(iSkip).Take(iTake);
and i took error: #foreach (interpretation interp in ViewBag.Interps) System.NotSupportedException: Explicit construction of entity type 'vslovare.Models.interpretation' in query is not allowed.
Is it really a way to take distinct rows and to have in finish rows like this:
idinterpretation | iddictionary | idword | meaning
1 1 1115 hello
5 1 1118 good bye
7 2 1119 yes
?
dictionaries:
dictionary table
iddictionary | dictionary_name
words:
word table
idword | word_name
interpretations:
interpretation table
idinterpretation | iddictionary | idword | meaning

I think your second attempt is almost there - you probably need to use a GroupBy clause to get this working within SQL.
Something like:
var query = from row in dc.interpretations
where row.iddictionary == iddict
group row by idword into grouped
select grouped.FirstOrDefault();
return query.OrderBy(w => w.word.word1).Skip(iSkip).Take(iTake);
On why your query is taking too long - in general, if your query is slow it will be because the data you are searching and returning is really large - or because it is poorly indexed at the database level. To help find out, it is analysing or profiling your query - see this article on MSDN http://msdn.microsoft.com/en-us/magazine/cc163749.aspx

Related

Filter the first n cases in SPSS based on condition

I have a database in SPSS structured like the following table:
ID
Gender
Age
Var1
Var...
1
0
7
3
...
2
1
8
4
...
3
1
9
5
...
4
1
9
2
...
I want to select only the first n (e.g.: 150) cases, where Gender = 1 and Age = 9, so in the table above the 3. and 4. case. How can I do it? Thanks!
compute filter_ = $sysmis.
compute counter_ = 0.
if $casenum=1 and (Gender = 1 and Age = 9) counter_ =1 .
do if $casenum <> 1.
if ~(Gender = 1 and Age = 9) counter_ = lag(counter).
if (Gender = 1 and Age = 9) counter_ = lag(counter) +1.
end if.
compute filter_ = (Gender = 1 and Age = 9 and counter<= 150).
execute.
I am not sure if this is the most efficient way, but it gets the job done. We use the counter_ variable to assign an order number for each record which satisfies the condition ("counting" records with meet the criteria, from the top of the file downwards). Then create a filter of the first 150 such records.
The below will select the first 150 cases where gender=1 AND age=9 (assuming 150 cases meet that criteria).
N 150.
SELECT IF (Gender=1 AND Age=9).
EXE .
Flipping the order of N and SELECT IF () would yield the same result. You can read more about N in the IBM documentation

How to return a count of fields with a given value in a record?

I have a database table with the following fields :
---------------------
FIELDS : | H1 | H2 | H3 | H4
---------------------
VALUES : | A | B | A | C
---------------------
For a given record (row), I would like to count the number of fields with a value of A. In the above, for example, there are two fields with a value of A, so the expected result would be : 2
How can I achieve this?
I am trying to answer the question from a database point of view.
You have a table with one or more rows and every row has in the four columns either an 'A' or something else. For a given row (or for many rows) you want to get the number of columns that have an 'A' in it.
As one commenter pointed out you can't sum letters but you can check whether or not a value is the one you are looking for and then count this occurence as a 1 or 0. Finally sum those values and return the sum.
SELECT (CASE H1 WHEN 'A' THEN 1 ELSE 0 END) +
(CASE H2 WHEN 'A' THEN 1 ELSE 0 END) +
(CASE H3 WHEN 'A' THEN 1 ELSE 0 END) +
(CASE H4 WHEN 'A' THEN 1 ELSE 0 END) AS number_of_a
FROM name_of_your_table;
For your example row this will return:
NUMBER_OF_A
===========
2
If you have more than one row you'll get the number of As for every row.
I test this it work Thanx for help.
SELECT count(H1) + count(H2) + count(H3) + count(H4) + count(H5) +
count(H6) + count(H7) + count(H8) as TOT
from Table T
where T.H1 = 'A' or T.H2 = 'A' or T.H3 = 'A' or T.H4 = 'A'
or T.H5 = 'A' or T.H6 = 'A' or T.H7 = 'A' or T.H8 = 'A'
group by T.ID
order by 1 DESC
Other solution ...

How to automatically format data to create a treemap in Google Sheets?

I want to create a treemap from dynamic data in google spreadsheets. So far, I succeeded to have a table in a format that Excel can use, but I don't know how to transform this table in a table that Google sheet can use to create this treemap
Excel can use this data. Not Google sheet.
My data looks like this:
Categories Item Value
__________ ______ _____
category_1 item_1 5
category_1 item_2 20
category_1 item_3 1
category_2 item_4 0
category_2 item_5 5
category_2 item_6 18
category_3 item_7 16
category_4 item_8 7
category_4 item_9 16
I would like to find a way to transform this data into something like the table below, which is usable by Google sheet.
Item Parent Value
__________ __________ _____
Categories 88
category_1 Categories 26
item_1 category_1 5
item_2 category_1 20
item_3 category_1 1
category_2 Categories 23
item_4 category_2 0
item_5 category_2 5
item_6 category_2 18
category_3 Categories 16
item_7 category_3 16
category_4 Categories 23
item_8 category_4 7
item_9 category_4 16
I did not find a way to do that yet and was wondering if anyone had faced the same problem.
Probably you can use this simple script function as an example:
function makeTree() {
var srcRange = SpreadsheetApp.getActiveSheet().getRange('A2:C10'),
tree = {'.Categories': 0}, key;
// Fill tree object with source data
srcRange.getValues().forEach(function(rowValues) {
// Add row value to the root
tree['.Categories'] += rowValues[2];
// Add it to "Category" level
key = 'Categories.' + rowValues[0];
if (tree[key] == undefined) {
tree[key] = rowValues[2];
} else {
tree[key] += rowValues[2];
}
// Add it to "Item" level too
key = rowValues[0] + '.' + rowValues[1];
if (tree[key] == undefined) {
tree[key] = rowValues[2];
} else {
tree[key] += rowValues[2];
}
});
// Format tree rows for output
var values = [];
for (key in tree) {
var subKeys = key.split('.');
values.push([subKeys[1], subKeys[0], tree[key]]);
}
// Fill target data rows
var targetRange = srcRange.offset(0, 4, values.length);
targetRange.setValues(values);
}
Here we collect all data in a single JS object, using composite string keys with a dot delimiter. Ready object is converted to the 2D-array before a target range filling. As a result we have both ranges on the same sheet:

how to group a date column based on date range in oracle

I have a table which contains a feedback about a product.It has feedback type (positive ,negative) which is a text column, date on which comments made. I need to get total count of positive ,negative feedback for particular time period . For example if the date range is 30 days, I need to get total count of positive ,negative feedback for 4 weeks , if the date range is 6 months , I need to get total count of positive ,negative feedback for each month. How to group the count based on date.
+------+------+----------+----------+---------------+--+--+--+
| Slno | User | Comments | type | commenteddate | | | |
+------+------+----------+----------+---------------+--+--+--+
| 1 | a | aaaa | positive | 22-jun-2016 | | | |
| 2 | b | bbb | positive | 1-jun-2016 | | | |
| 3 | c | qqq | negative | 2-jun-2016 | | | |
| 4 | d | ccc | neutral | 3-may-2016 | | | |
| 5 | e | www | positive | 2-apr-2016 | | | |
| 6 | f | s | negative | 11-nov-2015 | | | |
+------+------+----------+----------+---------------+--+--+--+
Query i tried is
SELECT type, to_char(commenteddate,'DD-MM-YYYY'), Count(type) FROM comments GROUP BY type, to_char(commenteddate,'DD-MM-YYYY');
Here's a kick at the can...
Assumptions:
you want to be able to switch the groupings to weekly or monthly only
the start of the first period will be the first date in the feedback data; intervals will be calculated from this initial date
output will show feedback value, time period, count
time periods will not overlap so periods will be x -> x + interval - 1 day
time of day is not important (time for commented dates is always 00:00:00)
First, create some sample data (100 rows):
drop table product_feedback purge;
create table product_feedback
as
select rownum as slno
, chr(65 + MOD(rownum, 26)) as userid
, lpad(chr(65 + MOD(rownum, 26)), 5, chr(65 + MOD(rownum, 26))) as comments
, trunc(sysdate) + rownum + trunc(dbms_random.value * 10) as commented_date
, case mod(rownum * TRUNC(dbms_random.value * 10), 3)
when 0 then 'positive'
when 1 then 'negative'
when 2 then 'neutral' end as feedback
from dual
connect by level <= 100
;
Here's what my sample data looks like:
select *
from product_feedback
;
SLNO USERID COMMENTS COMMENTED_DATE FEEDBACK
1 B BBBBB 2016-08-06 neutral
2 C CCCCC 2016-08-06 negative
3 D DDDDD 2016-08-14 positive
4 E EEEEE 2016-08-16 negative
5 F FFFFF 2016-08-09 negative
6 G GGGGG 2016-08-14 positive
7 H HHHHH 2016-08-17 positive
8 I IIIII 2016-08-18 positive
9 J JJJJJ 2016-08-12 positive
10 K KKKKK 2016-08-15 neutral
11 L LLLLL 2016-08-23 neutral
12 M MMMMM 2016-08-19 positive
13 N NNNNN 2016-08-16 neutral
...
Now for the fun part. Here's the gist:
find out what the earliest and latest commented dates are in the data
include a query where you can set the time period (to "WEEKS" or "MONTHS")
generate all of the (weekly or monthly) time periods between the min/max dates
join the product feedback to the time periods (commented date between start and end) with an outer join in case you want to see all time periods whether or not there was any feedback
group the joined result by feedback, period start, and period end, and set up a column to count one of the 3 possible feedback values
x
with
min_max_dates -- get earliest and latest feedback dates
as
(select min(commented_date) min_date, max(commented_date) max_date
from product_feedback
)
, time_period_interval
as
(select 'MONTHS' as tp_interval -- set the interval/time period here
from dual
)
, -- generate all time periods between the start date and end date
time_periods (start_of_period, end_of_period, max_date, time_period) -- recursive with clause - fun stuff!
as
(select mmd.min_date as start_of_period
, CASE WHEN tpi.tp_interval = 'WEEKS'
THEN mmd.min_date + 7
WHEN tpi.tp_interval = 'MONTHS'
THEN ADD_MONTHS(mmd.min_date, 1)
ELSE NULL
END - 1 as end_of_period
, mmd.max_date
, tpi.tp_interval as time_period
from time_period_interval tpi
cross join
min_max_dates mmd
UNION ALL
select CASE WHEN time_period = 'WEEKS'
THEN start_of_period + 7 * (ROWNUM )
WHEN time_period = 'MONTHS'
THEN ADD_MONTHS(start_of_period, ROWNUM)
ELSE NULL
END as start_of_period
, CASE WHEN time_period = 'WEEKS'
THEN start_of_period + 7 * (ROWNUM + 1)
WHEN time_period = 'MONTHS'
THEN ADD_MONTHS(start_of_period, ROWNUM + 1)
ELSE NULL
END - 1 as end_of_period
, max_date
, time_period
from time_periods
where end_of_period <= max_date
)
-- now put it all together
select pf.feedback
, tp.start_of_period
, tp.end_of_period
, count(*) as feedback_count
from time_periods tp
left outer join
product_feedback pf
on pf.commented_date between tp.start_of_period and tp.end_of_period
group by tp.start_of_period
, tp.end_of_period
, pf.feedback
order by pf.feedback
, tp.start_of_period
;
Output:
negative 2016-08-06 2016-09-05 6
negative 2016-09-06 2016-10-05 7
negative 2016-10-06 2016-11-05 8
negative 2016-11-06 2016-12-05 1
neutral 2016-08-06 2016-09-05 6
neutral 2016-09-06 2016-10-05 5
neutral 2016-10-06 2016-11-05 11
neutral 2016-11-06 2016-12-05 2
positive 2016-08-06 2016-09-05 17
positive 2016-09-06 2016-10-05 16
positive 2016-10-06 2016-11-05 15
positive 2016-11-06 2016-12-05 6
-- EDIT --
New and improved, all in one easy to use procedure. (I will assume you can configure the procedure to make use of the query in whatever way you need.) I made some changes to simplify the CASE statements in a few places and note that for whatever reason using a LEFT OUTER JOIN in the main SELECT results in an ORA-600 error for me so I switched it to INNER JOIN.
CREATE OR REPLACE PROCEDURE feedback_counts(p_days_chosen IN NUMBER, p_cursor OUT SYS_REFCURSOR)
AS
BEGIN
OPEN p_cursor FOR
with
min_max_dates -- get earliest and latest feedback dates
as
(select min(commented_date) min_date, max(commented_date) max_date
from product_feedback
)
, time_period_interval
as
(select CASE
WHEN p_days_chosen BETWEEN 1 AND 10 THEN 'DAYS'
WHEN p_days_chosen > 10 AND p_days_chosen <=31 THEN 'WEEKS'
WHEN p_days_chosen > 31 AND p_days_chosen <= 365 THEN 'MONTHS'
ELSE '3-MONTHS'
END as tp_interval -- set the interval/time period here
from dual --(SELECT p_days_chosen as days_chosen from dual)
)
, -- generate all time periods between the start date and end date
time_periods (start_of_period, end_of_period, max_date, tp_interval) -- recursive with clause - fun stuff!
as
(select mmd.min_date as start_of_period
, CASE tpi.tp_interval
WHEN 'DAYS'
THEN mmd.min_date + 1
WHEN 'WEEKS'
THEN mmd.min_date + 7
WHEN 'MONTHS'
THEN mmd.min_date + 30
WHEN '3-MONTHS'
THEN mmd.min_date + 90
ELSE NULL
END - 1 as end_of_period
, mmd.max_date
, tpi.tp_interval
from time_period_interval tpi
cross join
min_max_dates mmd
UNION ALL
select CASE tp_interval
WHEN 'DAYS'
THEN start_of_period + 1 * ROWNUM
WHEN 'WEEKS'
THEN start_of_period + 7 * ROWNUM
WHEN 'MONTHS'
THEN start_of_period + 30 * ROWNUM
WHEN '3-MONTHS'
THEN start_of_period + 90 * ROWNUM
ELSE NULL
END as start_of_period
, start_of_period
+ CASE tp_interval
WHEN 'DAYS'
THEN 1
WHEN 'WEEKS'
THEN 7
WHEN 'MONTHS'
THEN 30
WHEN '3-MONTHS'
THEN 90
ELSE NULL
END * (ROWNUM + 1)
- 1 as end_of_period
, max_date
, tp_interval
from time_periods
where end_of_period <= max_date
)
-- now put it all together
select pf.feedback
, tp.start_of_period
, tp.end_of_period
, count(*) as feedback_count
from time_periods tp
inner join -- currently a bug that prevents the procedure from compiling with a LEFT OUTER JOIN
product_feedback pf
on pf.commented_date between tp.start_of_period and tp.end_of_period
group by tp.start_of_period
, tp.end_of_period
, pf.feedback
order by tp.start_of_period
, pf.feedback
;
END;
Test the procedure (in something like SQLPlus or SQL Developer):
var x refcursor
exec feedback_counts(10, :x)
print :x

Inverting table

This is the table I have:
A B
1 Title1 | Title
2
3 0 | # of teachers
4
5 11 | # of students
6
7 Not active | Active?
8
9
10
11 Title2 | Title
12
13 3 | # of teachers
14
15 5 | # of students
16
17 Not active | Active?
18
19
20
21 Title3 | Title
22
23 10 | # of teachers
24
25 22 | # of students
26
27 Not active | Active?
I'd like to "invert" it in another sheet to have Title, # of teachers, # of students and Active? as headers and then the values under the right column (each entry in a separate row).
I was trying to use MATCH without much luck..
This retrieves just the first Title (every time):
=index(SheetWithTable!$A:$A,match("Title",SheetWithTable!$B:$B,0))
Please copy your sheet and in that copy select B1:B7, Copy, Paste special into D1 with Paste transpose. In D3, copied across to J3 and down to suit:
=index($A1:$A11,match(D$1,$B1:$B11,0))
Select all, Copy, Paste special, Paste values only. Filter Column B to deselect # of teachers only and delete all rows but Row 1. Clear filter. Delete Columns I, G, E, C, B, A.
Try the following formula in cell D1:
={{B1,B3,B5,B7};{filter(A:A,B:B=B1),filter(A:A,B:B=B3),filter(A:A,B:B=B5),filter(A:A,B:B=B7)}}
Or you can try:
={{"Title","# of teachers","# of students","Active?"};{filter(A:A,B:B="Title"),filter(A:A,B:B="# of teachers"),filter(A:A,B:B="# of students"),filter(A:A,B:B="Active?")}}
Have a look at the following screenshot:
If you have the 3 titles in a table, you can rotate it:
rotateArray = function(array) {
var newArray = [];
for (var i = 0; i < array[0].length; i++) {
newArray[i] = [];
for (var j = 0; j < array.length; j++) {
newArray[i].push(array[j][i]);
}
}
return newArray;
};
http://dtab.io/sheets/560b8efd6faeb39d2a70ad1e

Resources