SQL Modification - sql

I have a query (Main Query) is like this. I am executing this in Toad connected to Netezza DB.
SELECT *
FROM db1.schema1.Table1
WHERE (pd_num, pd_num_mtr, pd_num_prefix, sqr_num) IN
(SELECT pd_num,
pd_num_mtr,
pd_num_prefix,
max (sqr_num) sqr_num
FROM db1.schema1.table1
WHERE create_date >= '01/01/2012' AND cd_operator <> 'N'
GROUP BY pd_num, pd_num_mtr, pd_num_prefix)
When I execute this I get some 1 million records as my output. I further executed a query (Query2) to analyze the number of records belonging to the group as follows.
select pd_num_mtr,pd_num_prefix,count(*)
from db1.schema1.table1
GROUP BY pd_num, pd_num_mtr
order by count(*) desc
I get the below out put for this.
pd_num pd_num_mtr count(*)
001 15 500
002 15 200
003 30 100
Which means I have some 500 records pulled for the pd_num and pd_num_mtr combination with each of these records having an update_timestamp value. Now this needs to be modified as follows.
So among these 500 records, I need to pull only the one with maximum update_timestamp which will limit the count to only 1 record instead of 500.1 from 200 records, 1 record from 100 records with the max update timestamp value.
How can I modify the first query (main query) to acheive this? So that if the run the query2, I get the below as the output.
pd_num pd_num_mtr count(*)
001 15 1
002 15 2
003 30 3
Appreciate your help again. Thank you.

We will have to use row_number function for this. Assuming 'update_timestamp' as your timestamp column.
SELECT PD_NUM_MTR,PD_NUM_PREFIX
FROM
(
SELECT PD_NUM_MTR,PD_NUM_PREFIX,ROW_NUMBER() OVER (PARTITION BY PD_NUM_MTR,PD_NUM_PREFIX ORDER BY update_timestamp desc ) AS RK
FROM DB1.SCHEMA1.TABLE1
)
WHERE RK=1;

Related

Find rows with maximum count which have multiple joins in SQL

firstname lastname quantity object no datecol
soman mitra 50 1 31-05-2021
nitya sharma 100 2 31-05-2021
tanisha agarwal 200 3 31-05-2021
tarun mittal 300 4 31-05-2021
Above is the output of multiple joined tables. Now, I want to find the rows which have the maximum quantity
How can I do this since I have multiple table joined. Please help
If you just want the row(s) having the maximum quantity, then use TOP 1 WITH TIES:
SELECT TOP 1 WITH TIES -- current select list
FROM -- current query
ORDER BY quantity DESC;

SQL aggregate rows with same id , specific value in secondary column

I'm looking to filter out rows in the database (PostgreSQL) if one of the values in the status column occurs. The idea is to sum the amount column if the unique reference only has a status equals to 1. The query should not SELECT the reference at all if it has also a status of 2 or any other status for that matter. status refers to the state of the transaction.
Current data table:
reference | amount | status
1 100 1
2 120 1
2 -120 2
3 200 1
3 -200 2
4 450 1
Result:
amount | status
550 1
I've simplified the data example but I think it gives a good idea of what I'm looking for.
I'm unsuccessful in selecting only references that only have status 1.
I've tried sub-queries, using the HAVING clause and other methods without success.
Thanks
Here's a way using not exists to sum all rows where the status is 1 and other rows with the same reference and a non 1 status do not exist.
select sum(amount) from mytable t1
where status = 1
and not exists (
select 1 from mytable t2
where t2.reference = t1.reference
and t2.status <> 1
)
SELECT SUM(amount)
FROM table
WHERE reference NOT IN (
SELECT reference
FROM table
WHERE status<>1
)
The subquery SELECTs all references that must be excluded, then the main query sums everything except them
select sum (amount) as amount
from (
select sum(amount) as amount
from t
group by reference
having not bool_or(status <> 1)
) s;
amount
--------
550
You could use windowed functions to count occurences of status different than 1 per each group:
SELECT SUM(amount) AS amount
FROM (SELECT *,COUNT(*) FILTER(WHERE status<>1) OVER(PARTITION BY reference) cnt
FROM tc) AS sub
WHERE cnt = 0;
Rextester Demo

SQL - Select lowest values with group by and order by?

In my rankings database I have a table named times. I also have another table with authors. The authors have author id's (named ath_id inside the times table).
Records saved in times table:
id ath_id brand_id time date
------------- ------------ -------------- -------------- --------------
65125537 5384729 3 44741 May 8 2014
72073658 4298584 1 1104 Jun 28 2015
86139060 4298584 2 2376 Nov 20 2016
92237079 4298584 1 1115 Jun 24 2017
92237082 4298584 1 1104 Jun 24 2017
93436362 5384729 12 376492 Dec 31 2012
What I want to achieve
I'd like to retrieve an ordered list of the times that belong to the author (by the author id). I'd like to order them by brand_id, and I only want the records with the lowest time value.
Also, when there are multiple records with the same brand_id and the same time value, I'd like the list to be ordered by date. So the record with the latest date will be last.
What I have
I currently use this query: SELECT * FROM times WHERE ath_id = 4298584 GROUP BY brand_id ASC.
It works great, but it limits records with the same brand_id to 1, and thereby it limits records with the same time, even when multiple records have the lowest time value.
To sum it up
So in the case of the example above. When I select all the records with ath_id = 4298584, I'd like to retrieve the following ordered list:
id ath_id brand_id time date
------------- ------------ -------------- -------------- --------------
72073658 4298584 1 1104 Jun 28 2015
92237082 4298584 1 1104 Jun 24 2017
86139060 4298584 2 2376 Nov 20 2016
This is my first time doing a bit more advanced SQL queries. I'm working with Laravel, so giving both a raw SQL solution and a Laravel solution using the Laravel Query Builder wouldn't do any harm.
You could try using a derived table to get the min time for an ath_id and brand_id. Then join it back to your original table to get the rest of the data.
SELECT t.*
FROM times t
JOIN (SELECT ath_id, brand_id, MIN(time) AS time FROM dbo.times GROUP BY ath_id, brand_id) b
ON t.ath_id = b.ath_id AND t.brand_id = b.brand_id AND t.time = b.time
WHERE t.ath_id = 4298584
ORDER BY t.brand_id ASC, t.date DESC
This is another way you can do it. Although the output would be similar to SQLChao's answer, but the difference is that the inner query is creating and assigning ranks to the combination of ath_id,brand_id and date followed ordered by time. Then in outer query, you can use a filter to separate the rank 1. So basically you are replicating row_number() function.
You can use rnk=1 to rnk <= n in case you want first n records for your combination. But in you case, SQLChao's answer would be faster.
select t3.id,t3.ath_id,t3.brand_id,t3.time,t3.date
from times1 t3
inner join
(
select t1.ath_id,t1.brand_id,t1.date,t1.time,count(*) as rnk
from times1 t1
inner join times1 t2
on t1.ath_id=t2.ath_id
and t1.brand_id=t2.brand_id
and t1.date=t2.date
and t1.time >= t2.time
where t1.ath_id=4298584
group by t1.ath_id,t1.brand_id,t1.date,t1.time
) t4
on t3.ath_id=t4.ath_id
and t3.brand_id=t4.brand_id
and t3.date=t4.date
and t3.time = t4.time
and t4.rnk=1
;

SQL counting query

Sorry if this is a basic question.
Basically, I have a table that is as follows, below is a basic sample
store-ProdCode-result
13p I10x 5
13p I20x 7
13p I30x 8
14a K38z 23
17a K38z 23
my data set has nearly 100,000 records.
What I'm trying to do is, for every store find the top 10 prodCode.
I am unsure of how to do this but what I tried was:
select s_code as store, prod_code,count (prod_code)
from top10_secondary
where prod_code is not null
group by store,prod_code
order by count(prod_code) desc limit 10
this is giving me something completely different and i'm unsure on how I go about achieving my final result.
All help is appreciated.
Thanks
The expected output should be: for every store(s_code) display the top 10 prodcode
so:
store--prodcode--result
1a abc 5
1a abd 4
2a dgf 1
2a ldk 6
.(10 times until next store code)
You can use the table twice in the FROM clause, once for the data, and once to get a count of how many records have fewer results for that store.
SELECT a.s_code, a.prod_code, count(*)
FROM top10_secondary a
LEFT OUTER JOIN top10_secondary b
ON a.s_code = b.s_code
AND b.result < a.result
GROUP BY a.s_code, a.prod_code
HAVING count(*) < 10
With this technique though, you may get more than 10 records per store if the 10th result value exists multiple times. Because the limit rule is simply "include record as long as there are less than 10 records with result values than mine"
It looks like in your case, "result" is a ranking, so they would not be duplicated per store.
This is a good case for Window functions.
SELECT
s_code,
prod_code,
prod_count
FROM
(
SELECT
s_code,
prod_code,
prod_count,
RANK() OVER (PARTITION BY s_code ORDER BY prod_Count DESC) as prod_rank
FROM
(SELECT s_code as store, prod_code, count(prod_Code) prod_count FROM table GROUP BY s_code, prod_code) t1
) t2
WHERE prod_rank <= 10
The inner most query gets the count of each product at the store. The second inner more query determines the rank for those products for each store based on that count. Then the outer most query limits the results based on that rank.
o

MS Access query table without primary key

Claim# Total ValuationDt
1 100 1/1/12
2 550 1/1/12
1 2000 3/1/12
2 100 4/1/12
1 2100 8/1/12
3 200 8/1/12
3 250 11/1/12
Using MS Access, I need a query that returns only claims which have been valuated greater than $500 at some point in that claim's life time. In this example, the query should return
Claim# Total ValuationDt
1 100 1/1/12
2 550 1/1/12
1 2000 3/1/12
2 100 4/1/12
1 2100 8/1/12
because claim# 1 was valuated greater than $500 on 3/1/12, claim# 2 was valuated greater than $500 on 1/1/12, and claim# 3 was never valuated greater than $500.
You can use IN:
SELECT *
FROM Table1
WHERE Claim IN (SELECT Claim
FROM Table1
WHERE Total > 500)
Sql Fiddle Demo
Try this:
Select * from table where claim in (Select claim from table where total > 500)
Here table is the name of your table.
This could be the solution
SELECT distinct *
FROM YourTableName
WHERE claim# IN (SELECT DISTINCT claim#
FROM YourTableName
WHERE total > 500)
ORDER BY 3;
Optionally order by
This should work
Select DISTINCT Claim FROM yourtable Where Total > 500
EDIT:
In the case that my initial answer does not fulfill your requirements, then you can use a sub-query. A subquery is a query inside your query (nested queries). The reason we have to do it like that is because if you use something like
Select * FROM yourtable Where Total > 500
Then the result set would only be those moments where the total of the claim was higher than 500, but it would not indicate other moments where it was less or equal than 500.
Therefore, as others have stated, you use a subquery like:
SELECT *
FROM Table1
WHERE Claim IN (SELECT Claim
FROM Table1
WHERE Total > 500)
Note: see that there is a query after the IN keyword, so we have nested queries (or subquery if you prefer).
Why does it work? well, because:
SELECT Claim
FROM Table1
WHERE Total > 500
Will return every claim (only the number of the claim) in which the total was greater than 500 at some point. Therefore, this query will return 1 and 2. If you substitute that in the original query you get:
SELECT *
FROM Table1
WHERE Claim IN (1, 2)
Which will get you every column of every row with Claim numbers equal to either 1 or 2.
You can identify which [Claim#] values satisfy your condition ...
SELECT DISTINCT [Claim#]
FROM YourTable
WHERE [Total] > 500
If that was correct, use it as a subquery which you INNER JOIN to your table, to restrict the result set to only those claims.
SELECT y.[Claim#], y.[Total], y.[ValidationDt]
FROM YourTable AS y
INNER JOIN
(
SELECT DISTINCT [Claim#]
FROM YourTable
WHERE [Total] > 500
) AS sub
ON y.[Claim#] = sub.[Claim#];
Compare this approach vs. the IN() suggestions and see whether you notice any difference in execution speed.
You should be able to use
SELECT [Claim#],[Total],[ValidationDt]
FROM yourtable
WHERE [Claim#] IN (SELECT [Claim#]
FROM yourtable
WHERE Total >= 500)
Should return all values >= 500 for any ValidationDt.