Ignoring records for certain criteria - sql

I have data as below,
ACCOUNT
FLAG
asdf
1
asdf
2
asdf
3
kjhj
1
qwer
1
qwer
1
need to get output:
ACCOUNT
FLAG
kjhj
1
qwer
1
situation is that need to get records that have only "1" in 2nd column. If they have any other value other than "1", need to ignore all records for particular 1st column.
can you plz suggest a query
tried group by but didn't find option

Group to a single account per output row, then assert that all rows in a group must have flag=1 by using HAVING with both min and max.
SELECT
account,
MIN(flag) flag
FROM
your_table
GROUP BY
account
HAVING
MIN(flag) = 1
AND MAX(flag) = 1
Some people prefer the following and being more understandable, and it also causes a NULL row to exclude the group...
HAVING
MIN(CASE WHEN flag=1 THEN 1 ELSE 0 END) = 1

Related

How to check the count of each values repeating in a row

I have two tables. Data in the first table is:
ID Username
1 Dan
2 Eli
3 Sean
4 John
Second Table Data:
user_id Status_id
1 2
1 3
4 1
3 2
2 3
1 1
3 3
3 3
3 3
. .
goes on goes on
These are my both tables.
I want to find the frequency of individual users doing 'status_id'
My expected result is:
username status_id(1) status_id(2) status_id(3)
Dan 1 1 1
Eli 0 0 1
Sean 0 1 2
John 1 0 0
My current code is:
SELECT b.username , COUNT(a.status_id)
FROM masterdb.auth_user b
left outer join masterdb.xmlform_joblist a
on a.user1_id = b.id
GROUP BY b.username, b.id, a.status_id
This gives me the separate count but in a single row without mentioning which status_id each column represents
This is called pivot and it works in two steps:
extracts the data for the specific field using a CASE statement
aggregates the data on users, to make every field value lie on the same record for each user
SELECT Username,
SUM(CASE WHEN status_id = 1 THEN 1 END) AS status_id_1,
SUM(CASE WHEN status_id = 2 THEN 1 END) AS status_id_2,
SUM(CASE WHEN status_id = 3 THEN 1 END) AS status_id_3
FROM t2
INNER JOIN t1
ON t2.user_id = t1._ID
GROUP BY Username
ORDER BY Username
Check the demo here.
Note: This solution assumes that there are 3 status_id values. If you need to generalize on the amount of status ids, you would require a dynamic query. In any case, it's better to avoid dynamic queries if you can.

Is there a way to count the number of values in column?

I am a newbie studying MSSQL and Database.
I am trying to write a SQL query to count values in the column.
Following table is original one.
name value
----------
A 1
A 1
A 2
B 1
B 2
I want to get a table like this.
name one two
--------------
A 2 1
B 1 1
A has two 1 and one 2 and B has one 1 and 2. It seems I can accomplish it using COUNT built-in function. I tried but failed. Is there any idea to do it?
use conditional aggregation
select name, sum(case when value=1 then 1 else 0 end) as one,
sum(case when value=2 then 1 else 0 end) as two
from table_name group by name

Use case after order by

I was reading an sql book, one of questions is:
Write a query against the Sales.Customers table that returns for each customer the customer ID and region. Sort the rows in the output by region, having NULL marks sort last (after non-NULL values).Note that the default sort behavior for NULL marks in T-SQL is to sort first (before non-NULL values).
And the answer is :
SELECT custid, region
FROM Sales.Customers
ORDER BY
CASE WHEN region IS NULL THEN 1 ELSE 0 END, region;
I can kind of get the idea but still confused, let's take the record with custid = 9 for instance:
since custid 9 has a null region, in the case cstatement return 1, so the query is sth like:
ORDER BY 1, region
which is equivalent to:
ORDER BY custid, region --because custid is the first column
so how come the custid 9 is not before custid 10(the second record in the output)? isn't that output needs to order by custid first, so 9 is before 10?
Your interpretation is incorrect. The 1 is simple a number, not a column reference.
The query is equivalent to:
SELECT custid, region
FROM (SELECT c.*,
(CASE WHEN region IS NULL THEN 1 ELSE 0 END) as region_is_null
FROM Sales.Customers c
) c
ORDER BY region_is_null, region;
This is an important distinction about numbers in the ORDER BY. The expression:
ORDER BY 1
refers to the first column. However,
ORDER BY 1 + 0
is simply a numeric expression that returns the constant 1 -- and will result in an error in SQL Server (which does not allow constants in ORDER BY).
so the query is sth like
ORDER BY 1, region
No this is incorrect. The expression CASE WHEN region IS NULL THEN 1 ELSE 0 END is evaluated per-row; and the 1 is a value instead of column position. Column position inside ORDER BY can only specified only as a literal and not as an expression. So this:
custid region
8 NULL
9 NULL
10 BC
42 BC
45 CA
Becomes:
custid region case...
8 NULL 1
9 NULL 1
10 BC 0
42 BC 0
45 CA 0
And the sorted results could be:
custid region case...
10 BC 0
42 BC 0
45 CA 0
8 NULL 1
9 NULL 1
Or:
custid region case...
42 BC 0
10 BC 0
45 CA 0
9 NULL 1
8 NULL 1
You can try below - in your case 0 will be comign first then 1 so you need to change the order of the value, or you can do desc order if you don't want to change the value
SELECT custid, region
FROM Sales.Customers
ORDER BY
CASE WHEN region IS NULL THEN 0 ELSE 1 END, region
The idea is to use CASE statement to create a calculate virtual column to mark the nulls as 0 and none nulls as 1 and then sort accordingly.
if you use 0 in the order by clause you will get an error because you don't have a column at position of 0, also if you reorder the selected columns the result will be the same.
so the output of case statement is not a position of column it's a calculated column.
customer_id region marker
not important if null 0
ORDER BY CASE
WHEN region IS NULL THEN
1
ELSE
0
END,
region
is not equivalent to
ORDER BY 1,
region
because in the second one the first column to sort by is always constant, whereas in the first it can change depending on the CASE.
And
ORDER BY 1,
region
is also not equivalent to
ORDER BY custid,
region
again in the first the 1 is constant but custid is variable.
What
ORDER BY CASE
WHEN region IS NULL THEN
1
ELSE
0
END,
region
does is to "generate" a new column to sort by depending on the content of region. That new column gets 1 when region is null 0 otherwise. If you imagine this new column in the table it would look like
custid | region | new column
...
10 | BC | 0
...
9 | NULL | 1
...
Now if this gets sorted by the new column and the region the customer with ID 10 comes before the customer with ID 9 because the one with ID 10 has the lower value for the new column -- 0 against the 1 from the customer with the ID 9.

SQL to pick the next value

I have a table of values. Each value may have 1 or more entry, but only 1 should be active at any one time. The table has a primary INT ID
I need a method to make the 'current' value inactive and make the 'next' value the active value. If the current active value is the last active, instead make the first value active. Values with only 1 entry will always be active.
The sequence should work like below
Is anyone able to provide a way to achieve this?
You should not be showing runs in separate columns. Your data should put this information in separate rows. So your data should have a separate set of rows for each run:
id value run active
1 Apple 1 1
2 Apple 1 0
3 Apple 1 0
4 Banana 1 1
5 Banana 1 0
6 Cherry 1 1
1 Apple 2 0
2 Apple 2 1
3 Apple 2 0
4 Banana 2 0
5 Banana 2 1
6 Cherry 2 1
You can add the next run as:
with r as
select t.*, max(run) over () as max_run,
row_number() over (partition by run, value order by id) as seqnum,
lag(active) over (partition by run, value order by id) as prev_active
from runs
)
insert into runs (id, value, run, active)
select id, value, max_run + 1,
(case when prev_active = 1 then 1
when prev_active is null or seqnum = 1 then 1
else 0
end) as active
from r
where run = max_run;
Simply make a check, that is select id from the table is not max(id) of that table, then update the log to inactive and then update the id+1 to active.
And if select id from the table is max(ID) then simply update that row to inactive and update min(ID) to active.
build the query, itll be fun.

TSQL query to retrieve flagged/total rows

I'm struggling to find a solution to the following problem.
Assume, one has a table like this
COL1 FLAG
aaa 1
aaa 0
aaa 1
bbb 0
I need to write a query to get the following output:
COL1_VALUE FLAGGED TOTAL
aaa 2 3
bbb 0 1
where FLAGGED column contains the total count of the 'aaa' row values for which FLAG=1, and TOTAL column is the total number of rows containing 'aaa', in other words find how many rows containing 'aaa' are flagged in relation to total number of rows containing 'aaa'. Is it possible with a single query? (i.e. without using temp tables etc.)
(MSSQL2008)
SELECT COL1 AS COL1_VALUE,
COUNT(CASE WHEN FLAG = 1 THEN 1 END) AS FLAGGED,
COUNT(*) AS TOTAL
FROM YourTable
GROUP BY COL1
SELECT COL1, SUM(FLAG) AS FLAGGED, Count(*) AS TOTAL from tbl GROUP BY COL1
SELECT Tab.COL1 AS COL1_VALUE,
SUM(CASE WHEN Tab.FLAG = 1 THEN 1 ELSE 0 END) AS FLAGGED,
COUNT(*) AS TOTAL
FROM Tab
GROUP BY Tab.COL1