Wrong predicted SQL Server query outcome - sql-server

I'm learning for an SQL server exam and I got these questions I answered wrong, but I don't understand why the right answers are right and how you get these.
nr naam aantal chef
1 Anouk 14 2
2 Hans 14 NULL
3 Ali 13 5
4 Kees 12 5
5 Ben 3 2
nr soort stad chef
1 cursus DenHaag 2
2 cursus Amsterdam NULL
3 congres NewYork 5
4 lezing Utrecht 5
nr werknemer reis aantal datum bedrag
01 1 4 8 17-04-2013 420,56
02 3 3 5 05-04-2013 825,80
03 1 1 5 10-04-2013 140,00
04 null 2 2 10-04-2013 156,75
05 4 4 8 17-04-2013 328,90
06 5 3 5 05-04-2013 560,45
The 2 questions are:
a.
SELECT naam
FROM werknemer
WHERE nr NOT IN (SELECT werknemer
FROM declaratie);
b.
SELECT naam, COUNT(*)
FROM werknemer w LEFT OUTER JOIN declaratie d ON w.nr = d.werknemer
GROUP BY naam;
My answers are:
a: Hans
b: naam count(*)
Anouk 2
Hans 0
Ali 1
Kees 1
Ben 1
But the right answers are:
a: none
b: naam count(*)
Anouk 2
Hans 1
Ali 1
Kees 1
Ben 1
Can someone explain me what I probably missed?

a) is because performing any kind of NOT IN (1,NULL,3,4,5) returns a NULL results set because SQL cannot say whether any given value is not equal to NULL and thus effectively returns "I don't know". There is an excellent explanation of this on Stack Overflow.
The reason b) is wrong is that you are LEFT JOINing from werknemer. Thus all rows from werknemer are returned - including Hans. COUNT(*) will return a count of rows pertaining to that individual so Hans returns 1. Were you to COUNT(d.werknemer) then Hans would be 0 as all declaratie columns would be NULL for Hans because the JOIN predicate would not be met.

It's very likely that what you miss is that there is no way to compare NULL and INT using '='. This makes your result different, you are considering that comparing 2 (Hans) with NULL from declaratie will return false. You should try running this query to see what do I mean:
if 1=null or 1=1 print 'true' else print 'false'
if 1=null and 1=1 print 'true' else print 'false'

Ok, so a is wrong cuz of the null.
You cant use in(1,2,3 ,null,5)
That will return a nulled resuld and you will recieve none.
For b, because you use the left join it means that you get the entire original table with all of the values of the second one. So it means that you get a row for hans but all nulls im the left side because there is no match (but you still count it as a row)

Related

how to count classses in columns

I'm trying to make a query and i'm having a bad time with one thing. Suppose I have a table that looks like this:
id
Sample
Species
Quantity
Group
1
1
AA
5
A
2
1
AB
6
A
3
1
AC
10
A
4
1
CD
15
C
5
1
CE
20
C
6
1
DA
13
D
7
1
DB
7
D
8
1
EA
6
E
9
1
EF
4
E
10
1
EB
2
E
In the table I filter to have just 1 sample (but i have many), it has the species, the quantity of that species and a functional group (there are only five groups from A to E). I would like to make a query to group by the samples and make columns of the counts of the species of certain group, something like this:
Sample
N_especies
Group A
Group B
Group C
Group D
Group E
1
10
3
0
2
2
3
So i have to count the species (thats easy) but i don't know how to make the columns of a certain group, can anyone help me?
You can use PIVOT :
Select a.Sample,[A],[B],[C],[D],[E], [B]+[A]+[C]+[D]+[E] N_especies from
(select t.Sample,t.Grp from [WS_Database].[dbo].[test1] t) t
PIVOT (
COUNT(t.Grp)
for t.Grp in ([A],[B],[C],[D],[E])
) a

Recursive CTE help - how do you code this non-hierarchal sequence?

I'm trying to write a recursive CTE for a table that does not have a hierarchy. Meaning that there is no NULL in the family of IDs that are related.
For example table looks like this:
So it looks like this:
AccountID Account_RelationshipID
--------------------------------
1 2
2 4
4 6
6 11
11 1
15 17
17 19
19 15
So 1 relates to 2. 2 relates to 4. 4 relates to 6. 6 relates to 11. And then 11 loops back to ID of 1.
Then there is a new family. 15 relates to 17. 17 relates to 19. and then 19 goes back to 15.
There is also a separate Account_Detail table that has the account date:
AccountID AccountName AccountDate
-------------------------------------
1 Dave 1/1/2012
2 Dave 1/1/2013
4 Dave 1/1/2014
6 Dave 1/1/2015
11 Dave 1/1/2016
15 Paul 7/1/2015
17 Paul 7/1/2016
19 Paul 7/1/2017
I tried writing this as my code:
WITH C AS
(
SELECT
AR.AccountID,
AR.Account_RelationshipID,
AD.AccountDate
FROM
Account_Relationship AR
INNER JOIN
Account_Detail AD ON AD.AccountID = AR.AccountID
UNION ALL
SELECT
AR2.AccountID,
AR2.Account_RelationshipID,
AD.AccountDate
FROM
Account_Relationship AR2
INNER JOIN
Account_Detail AD2 ON AD2.Account_ID = AR2.Account_ID
INNER JOIN
C ON C.AccountID = AR2.Account_relationshipID
WHERE
AD.AccountDate < AD2.AccountDate
)
Obviously this code is totally wrong. This is as far as I've gotten. This code will loop infinitely.
I was thinking I could break the loop by adding a function that states when the AccountDate of the next AccountID in the loop is less than the AccountDate of the last AccountID, to break the loop and go to the next one.
Also, how do you get it to go to the next "family" of accountIDs in the loops (Paul in this case)? All the videos and tutorials I've seen about Recursive CTEs just teach how to do it for one family - usually with a hierarchical structure that breaks at NULL as well.
Help!!

How to aggregate number of notes sent to each user?

Consider the following tables
group (obj_id here is user_id)
group_id obj_id role
--------------------------
100 1 A
100 2 root
100 3 B
100 4 C
notes
obj_id ref_obj_id note note_id
-------------------------------------------
1 2 10
1 3 10
1 0 foobar 10
1 4 20
1 2 20
1 0 barbaz 20
2 0 caszes 30
2 1 30
4 1 70
4 0 taz 70
4 3 70
Note: a note in the system can be assigned to multiple users (for instance: an admin could write "sent warning to 2 users" and link it to 2 user_ids). The first user the note gets linked to is stored differently than the other linked users. The note itself is linked to the first linked user only. Whenever group.obj_id = notes.obj_id then ref_obj_id = 0 and note <> null
I need to make an overview of the notes per user. Normally I would do this by joining on group.obj_id = notes.obj_idbut here this goes wrong because of ref_obj_id being 0 (in which case I should join on notes.obj_id)
There are 4 notes in this system (foobar, barbaz, caszes and taz).
The desired output is:
obj_id user_is_primary notes_primary user_is_linked notes_linked
-------------------------------------------------------------------
1 2 10;20 2 30;70
2 1 30 2 10;20
3 0 2 10;70
4 1 70 1 20
How can I get to this aggregated result?
I hope that I was able to explain the situation clearly; perhaps it is my inexperience but I find the data model not the most straightforward.
Couldn't you simply put this in the ON clause of your join?
case when notes.ref_obj_id = 0 then notes.obj_id else notes.ref_obj_id end = group.obj_id

"ColumnName" is not a recognized table hints option. error while Joining a table value function with a query

I have a sample table like the one below
table1
chktid ToUser
1 3
2 6
3 3
4 1
chkid is the parentId and sometimes this parent has childs and each of them, has sub-childs and so on
I have written a function to return all the childs and sub-childs of the particular chktid. Calling my function dbo.hierychyreturnfn(chktid) with different chktid as input parameter, I am getting the following results
For chktid = 1 and so select * from dbo.hierychyreturnfn(1), the output is:
chkchildid
10
11
12
13
For chktid = 2 and so select * from dbo.hierychyreturnfn(2), the output is:
chkchildid
14
15
16
For chktid = 3 and so select * from dbo.hierychyreturnfn(3), the output is:
chkchildid
19
For chktid = 4 and so select * from dbo.hierychyreturnfn(4), it returns no rows since chkid=4 has no childs.
My question is: Is there any way to join the function and table 1 and return all results?
My expected out put is:
chkid ToUser chkchildid
1 3 10
1 3 11
1 3 12
1 3 13
2 6 14
2 6 15
2 6 16
3 3 19
I am trying to use cross apply for getting this
SELECT a.chkid
,a.ToUser
,b.chkchildid
FROM table1 a
CROSS APPLY dbo.hierychyreturnfn(1) b // need to join table1 and pass each chkid
But I don't know how to pass each chkid to hierychyreturnfn(). I am stuck here. I have also tried code below also but it gives an error
"chkid" is not a recognized table hints option. If it is intended as a
parameter to a table-valued function or to the CHANGETABLE function,
ensure that your database compatibility mode is set to 90.
SELECT a.chkid
,a.ToUser
,b.chkchildid
FROM table1 a
CROSS APPLY dbo.hierychyreturnfn(chkid) b
Please help me to solve this issue.

Condense multiple rows to single row with counts based on unique values in sqlite

I am trying to condense a table which contains multiple rows per event to a smaller table which contains counts of key sub-events within each event. Events are defined based on unique combinations across columns.
As a specific example, say I have the following data involving customer visits to various stores on different dates with different items purchased:
cust date store item_type
a 1 Main St 1
a 1 Main St 2
a 1 Main St 2
a 1 Main St 2
b 1 Main St 1
b 1 Main St 2
b 1 Main St 2
c 1 Main St 1
d 2 Elm St 1
d 2 Elm St 3
e 2 Main St 1
e 2 Main St 1
a 3 Main St 1
a 3 Main St 2
I would like to restructure the data to a table that contains a single line per customer visit on a given day, with appropriate counts. I am trying to understand how to use SQLite to condense this to:
Index cust date store n_items item1 item2 item3 item4
1 a 1 Main St 4 1 3 0 0
2 b 1 Main St 3 1 2 0 0
3 c 1 Main St 1 1 0 0 0
4 d 2 Elm St 2 1 0 1 0
5 e 2 Main St 2 2 0 0 0
6 a 3 Main St 2 1 1 0 0
I can do this in excel for this trivial example (begin with sumproduct( cutomer * date) as suggested here, followed by cumulative sum on this column to generate Index, then countif and countifs to generate desired counts).
Excel is poorly suited to doing this for thousands of rows, so I am looking for a solution using SQLite.
Sadly, my SQLite kung-fu is weak.
I think this is the closest I have found, but I am having trouble understanding exactly how to adapt it.
When I tried a more basic approach to begin by generating a unique index:
CREATE UNIQUE INDEX ui ON t(cust, date);
I get:
Error: indexed columns are not unique
I would greatly appreciate any help with where to start. Many thanks in advance!
To create one result record for each unique combination of column values, use GROUP BY.
The number of records in the group is available with COUNT.
To count specific item types, use a boolean expression like item_type=x, which returns 0 or 1, and sum this over all records in the group:
SELECT cust,
date,
store,
COUNT(*) AS n_items,
SUM(item_type = 1) AS item1,
SUM(item_type = 2) AS item2,
SUM(item_type = 3) AS item3,
SUM(item_type = 4) AS item4
FROM t
GROUP BY cust,
date,
store

Resources