Selecting two tables and ranking - sql

I'm attempting to select two tables that have the same columns and combining them into 1 which will rank column SalesAmount from Highest to Lowest. I've attempted to do this by using UNION ALL but currently, the returned select is ranking them both separately.
TableTwo has a different ReportId value then the values in TableOne.
Here is an example of the returned select from TableOne statement:
StateId
ReportTitle
ReportId
SalesAmount
SalesRank
1
Online Sales in California
21
22
1
12
Online Sales in New York
21
13
2
23
Online Sales in Nevada
21
9
4
Here is an example of the returned select from TableTwo which only has 1 value:
StateId
ReportTitle
ReportId
SalesAmount
SalesRank
14
Online Sales in Michigan
91
11
3
I am now attempting to combine these two tables and rank them accordingly. when using UNION ALL Here is what is being returned:
StateId
ReportTitle
ReportId
SalesAmount
SalesRank
1
Online Sales in California
21
22
1
12
Online Sales in New York
37
13
2
23
Online Sales in Nevada
14
9
4
14
Online Sales in Michigan
91
11
3
The row Michigan is ranked 3. It is selecting both tables into 1 statement but not ranking them as I am trying to do. How can I achieve this? My expected results is having both tables be Ordered By SalesRank appropriately
Here is an example of my expected result:
StateId
ReportTitle
ReportId
SalesAmount
SalesRank
1
Online Sales in California
21
22
1
12
Online Sales in New York
37
13
2
14
Online Sales in Michigan
91
11
3
23
Online Sales in Nevada
14
9
4
Here is a query of example:
CREATE TABLE TableOne
(
StateId INT,
ReportTitle VARCHAR(100),
ReportId INT,
SalesAmount Money,
SalesRank INT
)
INSERT INTO TableOne (StateId,ReportTitle,ReportId,SalesAmount, SalesRank)
VALUES (1,'Online Sales in California',21, 22, 1),(12,'Online Sales in New York ',21, 13, 1), (1,'Online Sales in Nevada',21, 9, 4)
CREATE TABLE TableTwo
(
StateId INT,
ReportTitle VARCHAR(100),
ReportId INT,
SalesAmount Money,
SalesRank INT
)
INSERT INTO TableOne (StateId,ReportTitle,ReportId,SalesAmount, SalesRank)
VALUES (14,'Online Sales in Michigan',91, 11, 3)
SELECT * FROM TableOne
UNION ALL
SELECT * FROM TableTwo

Your attempt doesn't have an order by clause? So of course it won't be ordered. Add order by SalesRank e.g.
SELECT *
FROM TableOne
UNION ALL
SELECT *
FROM TableTwo
ORDER BY SalesRank
Note: Rows in tables are not stored or accessed in any determinable order. If order is important you must use an order by clause as part of your select.

Generally I like to see the actual column names in a SELECT so I added those and an ORDER BY on the SalesRank - not sure if you want the default ascending or descending.
SELECT
StateId
ReportTitle,
ReportId,
SalesAmount,
SalesRank
FROM TableOne
UNION ALL
SELECT
StateId
ReportTitle,
ReportId,
SalesAmount,
SalesRank
FROM TableTwo
ORDER BY SalesRank;

Related

SQL Querying of Data by grouping with only one main variable(Store) and finding the percentage of customers in other variable

Tables - Store
Stores
Date
Customer_ID
A
01/01/2020
1111
C
01/01/2020
1111
F
02/01/2020
1234
A
02/01/2020
1111
A
02/01/2020
2222
Tables - Customer
Customer_ID
Age_Group
Income_Level
1111
26-30
Low
1234
25 and below
Mid
2222
31-60
High
I want to know how I can get this output.
Stores
Age_Group
Percentage_by_Age
Income_Level
Percentage_By_Income
A
25 and below
10
Low
80
A
25 and below
10
Mid
10
A
25 and below
10
High
10
A
26 - 30
42
Low
15
A
26 - 30
42
Mid
65
A
26 - 30
42
High
20
A
31 - 60
48
Low
30
A
31 - 60
48
Mid
50
A
31 - 60
48
High
20
I am using SQL to query from different tables.
First I need to aggregate the number of customers by stores, then in each store, I want to find out how many customers visited Store A in a particular age group(25 and below), and how many of them are in which income level.
May I know how I can go about solving this query?
Thanks.
My current solution/thought process
SELECT
stores AS Stores,
Age_Group AS Age,
Income_Level AS Income
COUNT(DISTINCT(Customer_ID)) AS Number_of_Customers
FROM tables JOIN tables....
GROUP BY Stores, Ages, Income;
And then manually calculating the percentages.
But it doesn't seem right.
Is there a way to produce an example output table using just SQL?
As per your requirement, Common Table Expressions can be used . You can use below code to get the expected output.
WITH
data_for_percent_by_income AS (
SELECT
COUNT(customer_id) AS cus_count_in_per_income_level_and_agegrp,
Age_group AS age_g,income_level AS inc_lvl
FROM
`project.dataset.Customer2`
WHERE
customer_id IN (
SELECT customer_id
FROM
`project.dataset.Store5`
WHERE stores='A')
GROUP BY
Age_group,income_level),tot_cus_in_defined_income_level AS (
SELECT
COUNT(customer_id) AS cus_count_in_per_income_level,Age_group AS ag
FROM
`project.dataset.Customer2`
WHERE
customer_id IN (
SELECT
customer_id
FROM
`project.dataset.Store5`
WHERE stores='A')
GROUP BY
Age_group),
tot_cus_storeA AS(
SELECT
COUNT(*) AS tot_cus_in_A
FROM
`project.dataset.Customer2`
WHERE customer_id IN (
SELECT customer_id
FROM
`project.dataset.Store5`
WHERE stores='A') ),
final_view AS(
SELECT
ROUND(cus_count_in_per_income_level_and_agegrp*100/cus_count_in_per_income_level) AS p_by_inc,
age_g,inc_lvl
FROM
data_for_percent_by_income
INNER JOIN
tot_cus_in_defined_income_level
ON
data_for_percent_by_income.age_g=tot_cus_in_defined_income_level.ag )
SELECT
stores,tot_cus_in_defined_income_level.ag AS age_group,income_level,
ROUND(cus_count_in_per_income_level*100/tot_cus_in_A) AS percentage_by_age,
p_by_inc AS percentage_by_income
FROM
tot_cus_in_defined_income_level,tot_cus_storeA,`project.dataset.Customer2`,`project.dataset.Store5`
INNER JOIN
final_view
ON
age_group=final_view.age_g AND income_level=final_view.inc_lvl
WHERE
tot_cus_in_defined_income_level.ag = Age_group AND stores='A'
GROUP BY
stores,percentage_by_age,age_group,income_level,percentage_by_income
ORDER BY Age_group
I have attached the screenshots of the input table and output table.
Customer Table
Store Table
Output Table
SELECT
s.Stores AS Stores,
c.age_group AS Age,
a.income_level AS Affluence,
CAST(COUNT(DISTINCT c.Customer_ID) AS numeric)*100/SUM(CAST(COUNT(DISTINCT c.Customer_ID) AS numeric)) OVER(PARTITION BY s.Stores ) AS Perc_of_Members
This is what I did in the end.

How to join two tables and count records SQL

table 1 is maintable_KQPPJ : contains GroupID, Year, Name, VendorID. This table contains multiple records with the same GroupID
table 2 is cb_vendorinformation: contains GroupID and CompanyName
I would like to join both tables on GroupID. The output should only have GroupID, CompanyName, and Count. The Count is the distinct count of GroupID in maintable_KQPPJ.
I have the following code but it doesn't really give me the output I'm looking for.
SELECT maintable_KQPPJ.GROUPID, cb_vendorinformation.CompanyName, count(distinct maintable_KQPPJ.GROUPID)
FROM maintable_KQPPJ
JOIN cb_vendorinformation ON maintable_KQPPJ.GROUPID=cb_vendorinformation.GROUPID
maintable_KQPPJ:
GroupID Year VendorID Name
26 2019 9999 John
26 2020 2345 Jane
6 2018 3244 Jack
36 2021 3245 Jill
cb_vendorinformation:
GroupID CompanyName
26 Walmart
6 Target
36 Kroger
The output should look like
GroupID CompanyName Count
26 Walmart 2
6 Target 1
36 Kroger 1
You need group by and count(*)
SELECT maintable_KQPPJ.GROUPID
, cb_vendorinformation.CompanyName
, count(*)
FROM maintable_KQPPJ
JOIN cb_vendorinformation ON maintable_KQPPJ.GROUPID=cb_vendorinformation.GROUPID
GROUP BY maintable_KQPPJ.GROUPID
, cb_vendorinformation.CompanyName

Min per group in SQL but with a caveat

I've got this table in SQL below and I need to return "the car vendors that will never be used if the car purchaser is a rational person" or "The vendor for which all car prices are more expensive then others". I've tried to do the idea of joining with itself but I am unable to get it work. The resulting output should be vendor 3 since its price for car 3 and 4 is more expensive than the other option.
id car_vendor_id vendor_name car_id price
---------------------------------------------
1 1 Vendor 1 1 25000
2 1 Vendor 1 2 40000
3 2 Vendor 2 2 35000
4 2 Vendor 2 3 25000
5 3 Vendor 3 3 28000
6 3 Vendor 3 4 40000
7 4 Vendor 4 4 35000
8 4 Vendor 4 5 20000
9 5 Vendor 5 5 18000
10 5 Vendor 5 6 32000
11 6 Vendor 6 6 30000
12 6 Vendor 6 7 20000
One method is row_number() and aggregation:
select car_vendor_id, vendor_name
from (select t.*,
rank() over (partition by car_id order by price) as seqnum
from t
) t
group by car_vendor_id, vendor_name
having min(seqnum) > 1;
The having clause is selecting rows where the vendor has no cars that are "first" based on price.
The following query uses a CTE to work out the price order for each car, so the most expensive is 1.
It then excludes rows where there is a row for the vendor where they are not the most expensive, and lastly checks they are are not the only vendor for a car.
declare #Car table(Vendor int, Car int, Price int)
insert #Car values (1,1,25000),(1,2,40000),(2,2,35000),(2,3,25000),(3,3,28000),(3,4,40000),(4,4,35000),(4,5,20000),(5,5,18000),(5,6,32000),(6,6,30000),(6,7,20000)
;with Price as (
select *, row_number() over(partition by Car order by Price desc) as r from #Car Car
)
select * from Price
where not exists(select * from Price p2 where p2.Vendor=Price.Vendor and p2.r>1)
and Vendor not in (
select Vendor from #Car where Car in (select Car from #Car group by Car having count(*)=1)
)
Check on the next query:
declare #car table(Vendor int, Car int, Price int);
insert #car
values
(1,1,25000),(1,2,40000),(2,2,35000),(2,3,25000),
(3,3,28000),(3,4,40000),(4,4,35000),(4,5,20000),
(5,5,18000),(5,6,32000),(6,6,30000),(6,7,20000);
with
a as (
select
vendor, price,
count(*) over(partition by car) cq,
count(*) over(partition by vendor) vcq,
max(price) over(partition by car) xcp
from #car
)
select vendor
from a
where cq > 1 and xcp = price
group by vendor, vcq
having count(*) = vcq;
To try the query online, please click here.

Reconciliation Automation Query

I have one database and time to time i change some part of query as per requirement.
i want to keep record of results of both before and after result of these queries in one table and want to show queries which generate difference.
For Example,
Consider following table
emp_id country salary
---------------------
1 usa 1000
2 uk 2500
3 uk 1200
4 usa 3500
5 usa 4000
6 uk 1100
Now, my before query is :
Before Query:
select count(emp_id) as count,country from table where salary>2000 group by country;
Before Result:
count country
2 usa
1 uk
After Query:
select count(emp_id) as count,country from table where salary<2000 group by country;
After Query Result:
count country
2 uk
1 usa
My Final Result or Table I want is:
column 1 | column 2 | column 3 | column 4 |
2 usa 2 uk
1 uk 1 usa
...... but if query results are same than it shouldn't show in this table.
Thanks in advance.
I believe that you can use the same approach as here.
select t1.*, t2.* -- if you need specific columns without rn than you have to list them here
from
(
select t.*, row_number() over (order by count) rn
from
(
-- query #1
select count(emp_id) as count,country from table where salary>2000 group by country;
) t
) t1
full join
(
select t.*, row_number() over (order by count) rn
from
(
-- query #2
select count(emp_id) as count,country from table where salary<2000 group by country;
) t
) t2 on t1.rn = t2.rn

make many count () in one query

I have data set of call customer, I want to make count () to know:
Total number of calls for each customer
Total duration of call for each customer
Total of locations the customer he where in
This my data:
Phone no. - Duration In minutes - Location
1111 3 88
2222 4 33
3333 4 4
1111 7 55
3333 9 4
3333 7 3
the result of query:
phone no- Total number of records -Total duration of calls- Total of location
1111 2 10 2
2222 1 4 1
3333 3 20 2
This is almost similar to fthiella answer. Try like this
select PhoneNo,
count(*) as TotalNumberOfRecords,
sum(DurationInMinutes) as TotalDurationOfCalls,
count(distinct location) as TotalOfLocations from yourtablename
group by PhoneNo
You can use a GROUP BY query with basic aggregated functions, like COUNT(), SUM() and COUNT(DISTINCT) like this:
select phone_no, count(*), sum(duration), count(distinct location)
from tablename
group by phone_no
answer for your question is
select Phone no,count(Duration In minutes),sum(Duration In minutes),count(distinct Location) from Tablename group by Phone no order by Phone no;
I have made temporary table for testing and it gives same output as you mention. look following query :
declare #TEMP table (phone_no int, duration int, location int)
insert into #temp values(1111,3,88),(2222,4,33),(3333,4,4),(1111,7,55),(3333,9,4),(3333,7,3)
select phone_no, count(*), sum(duration), count(distinct location)
from #TEMP
group by phone_no
you just can consider this query :
select phone_no, count(*), sum(duration), count(distinct location)
from #TEMP
group by phone_no