SQL Server query with multiple HAVING conditions - ssms

Let's say we have a Table1:
ID Month Code
----------
1 Dec
1 Jan Yes
2 Dec
2 Jan
How do I SELECT ID's with (Dec and Jan) and missing a Yes code? I'd like my query to return ID 2 but not ID 1. I know I can't have an AND in the HAVING clause.

Try this query
SELECT ID FROM Table1 WHERE Month = "Dec" AND Code <> "yes" AND ID IN (SELECT ID FROM Table1 WHERE Month = "Jan" AND Code <> "yes")

Related

Extract column from SQL table based on another column if the same table

I m using POSTGRESQL.
Table of PURCHASES looks like this:
ID | CUSTOMER_ID | YEAR
1 1 2011
2 2 2012
3 2 2012
4 1 2013
5 3 2014
6 3 2014
7 3 2015
I need to extract 'ID' of the purchase with the latest 'date/year' for each CUSTOMER.
For example for CUSTOMER_ID 1 the year s 2013 which correcponds with id '4'.
I need to get ONE column as a return data structure.
PS. i m stuck with this kinda simple task )))
If you want one row per customer, you can use distinct on:
select distinct on (customer_id) id
from purchases
order by customer_id, year desc;
This returns one column which is an id from the most recent year for that customer.
This should work, but doesn't look too pretty...
SELECT DISTINCT ON(CUSTOMER_ID) ID FROM PURCHASES P
WHERE (CUSTOMER_ID,YEAR) =
(SELECT CUSTOMER_ID,MAX(YEAR) FROM PURCHASES WHERE CUSTOMER_ID = P.CUSTOMER_ID
GROUP BY CUSTOMER_ID);
So for input
ID | CUSTOMER_ID | YEAR
1 1 2011
2 2 2012
3 2 2012
4 1 2013
5 3 2014
6 3 2014
7 3 2015
It will return
id
4
2
7
Meaning:
For the lowest CUSTOMER_ID (it is 1) the id is 4 (year 2013)
Next we have CUSTOMER_ID (it is 2) the id is 2 (year 2012)
Lastly the CUSTOMER_ID (it is 3) the id is 7 (year 2015)
The idea behind this:
Group by CUSTOMER_ID
For each group select max(year)
While looping over all records - if Customer_id and year equals those from number 2. then select ID from this record.
Without DISTINCT ON(CUSTOMER_ID) it would return 2 records
for CUSTOMER_ID = 2, because for both years 2012 it would find some records while looping.
If you write in the beginning instead of:
SELECT DISTINCT ON(CUSTOMER_ID) ID FROM PURCHASES P
this code:
SELECT DISTINCT ON(CUSTOMER_ID) * FROM PURCHASES P
then you will see everything clearly.
Use row_number() analytic function with partition by customer_id to select by each customer with descending ordering by year ( if ties occur for year values [e.g. they're equal], then the below query brings the least ID values for each customer_id. e.g. 4, 2, 7 respectively )
WITH P2 AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY CUSTOMER_ID ORDER BY YEAR DESC) AS RN,
*
FROM PURCHASES
)
SELECT ID FROM P2 WHERE RN = 1
Demo

How do I "dedup" rows based on most recently updated

Lets say I have a table whose content looks like
ID Name Last Update
============================
1 A 1 JAN 2018
1 A 2 JAN 2018
1 A 3 JAN 2018
2 B 3 JAN 2018
2 B 6 JAN 2018
I want to get the result
ID Name Last Update
============================
1 A 3 JAN 2018
2 B 6 JAN 2018
How can I do it?
I tried to group by ID but, how do I get the most recent?
While #Nik's solution can work in situations where there are either no ties for the MAX(date) values (or it doesn't matter which tie value gets selected and whether this produces multiple output rows), an alternative approach is to group all records by ID sort all records belonging to one group by date in descending order and then pick the very first result row per group.
This can be achieved by using the SQL standard window function ROW_NUMBER() like this:
SELECT ID, NAME, DATE
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY ID
ORDER BY DATE DESC) RN
, ID
, NAME
, DATE
FROM <TABLE_NAME>
)
WHERE RN = 1;
You could use a query like this to get the results that you need:
SELECT *
FROM table
WHERE (ID, date) IN (SELECT
ID, MAX(Last Update)
FROM table
GROUP BY ID)

Select from Column A based on Column B

I have 4 tables joined together and this is the result of that query,
Name Year
Erin 2015
Erin NULL
Erin NULL
Sarah 2010
Peter 2011
The two columns are from two different tables. They both have an ID I can match. How do I narrow it down to this result,
Name Year
Erin 2015
Erin NULL
Erin NULL
When Year = 2015, I want all of Erin's.
SELECT Name
CASE WHEN Year = 2015 THEN
......
END
Rest of the columns I've selected
FROM Table
Joined with 4 other tables
WHERE
Stuff
What can I put in between the CASE statement.
It sounds like you want to see all the records from any name that has at least one record with a year = '2015'. If so, then:
SELECT Name, Year, Other_Columns
FROM Name N
JOIN YEAR Y on Y.ID = N.ID
WHERE N.ID IN (
SELECT ID
FROM YEAR
WHERE YEAR = '2015'
)
Put the same case when into the where clause:
select
case when .. then 'a' else 'b' end
from TABLE
where
(case when .. then 'a' else 'b' end) = 'b'
;

How do I `group by` rows and columns in SQLite3?

SQLite database table table1
user command date location
---------- ---------- ---------- ----------
user1 cmd1 2015-01-01 xxxdeyyy
user2 cmd1 2015-01-01 zzzfrxxx
user3 cmd1 2015-01-01 yyyukzzz
user1 cmd1 2015-01-01 xxxdezzz
...
Expected output
Output for where command='cmd1':
month users_de users_fr users_es
-------- -------- -------- --------
01 1 0 5
02 2 0 0
03 0 2 1
04 5 0 15
05 1 0 4
06 11 1 2
07 9 0 3
08 1 0 5
09 0 0 5
10 0 0 0
11 1 0 0
12 1 4 5
It is grouped by month (from column date) and also grouped by a substring in location (from column location).
Actual output
I can achieve this (per location):
month users_de
-------- --------
01 1
02 2
03 0
...
12 1
using this query:
select strftime('%m',date) as month, count(distinct user) as users_de
from table1
where command='cmd1' and location like '%de%'
group by strftime('%m',date);
I then repeat this query for the other locations (where ... and location='fr'):
month users_fr
-------- --------
01 0
02 0
03 2
...
12 4
and (where ... and location='es');
month users_es
-------- --------
01 5
02 0
03 1
...
12 5
Is there a way to have all the users_xx columns in one table (as output from SQLite and not through any external (downstream) processing)?
Am I thinking about this in the wrong way (grouping instead of subqueries in the top select)?
You can use the case statement to match each location and then if matches count the user.
select strftime('%m',date) as month,
CASE WHEN location='de' THEN count(distinct user) END users-de,
CASE WHEN location='fr' THEN count(distinct user) END users-fr,
CASE WHEN location='es' THEN count(distinct user) END users-es,
from table1
where command='cmd1'
group by strftime('%m',date),location;
I think you want conditional aggregation:
select strftime('%m',date) as month,
count(distinct CASE WHEN location like '%de%' THEN user END) as users_de,
count(distinct CASE WHEN location like '%fr%' THEN user END) as users__fr,
count(distinct CASE WHEN location like '%es%' THEN user END) as users_es
from table1
where command = 'cmd1'
group by strftime('%m',date);
Two notes:
like possibly isn't safe in this context. You have the country code embedded in the string, but the characters "de", "es", or "fr" could appear elsewhere in the string. Your question is not clear on better logic for this.
You should include the year in the date string, but your question specifically includes only the month.
Using query like this:
SELECT strftime('%m',date) AS month,
location,
count(distinct user) AS users-de,
count(distinct user) AS users-fr,
count(distinct user) AS users-es
FROM table1
WHERE command='cmd1' GROUP BY strftime('%m', date), location;

How to use MAX and TOP in SQL Query in ORACLE?

Suppose I have following table
ID ITEM QUANTITY DATE
1 A 50 Jan 3, 2013
2 B 80 Jan 1, 2013
3 C 70 Jan 5, 2013
4 D 80 Jan 4, 2013
I have to make a single query which will fetch the record which has highest quantity and highest date. For example, end result should be
4 D 80 Jan 4, 2013
Update: First of all I have to pick the records which have highest quantity. In this case it would be record no. 2 and 4. Then I have to again filter out from these two records which have highest date
How should I make SQL query in ORACLE?
To get those data you could write a query similar to this one:
select id
, item
, quantity
, date
from (select id
, item
, quantity
, date
from your_table
order by quantity desc, date desc
)
where rownum = 1