divide column from one table to column from another table - sql

I've two tables
TB_1 TB_3
Month Total Month Total
2012-01 6 2012-01 12
2013-02 6 2013-02 12
2014-03 10 2014-03 20
2015-04 10 2015-04 20
In result table I need follow result:
RESULT_TB
Month Total
2012-01 2
2013-02 2
2014-03 2
2015-04 2
I tried the following:
Select TB_3.total / TB_1.total
From TB_3, TB_1
But it does not work, tell me please, how to do?

Try this:
select t1.month,
case
when t1.total = 0
then null
else t2.total / t1.total
end total
from tb_1 t1
join tb_3 t2 on t1.month = t2.month
I used CASE to ensure if there is zero total in tb_1 table, the output comes as NULL instead of throwing a divide by zero error.

You only seem to need a proper JOIN condition:
Select t3.month, t3.total / t1.total
From TB_3 t3 JOIN
TB_1 t1
ON t3.month = t1.month;
Note: If the tables have different sets of months, then you might want some sort of outer join.
Also, Postgres does integer division when both operands are integers. It is unclear whether you want that or not. But if the values were "15" and "2", then the result would be "7" rather than "7.5".

You can try this code:
SELECT ISNULL(T1.Month,T2.Month) AS Month
, CASE WHEN ISNULL(T1.Total,0) = 0 THEN ISNULL(T2.Total,0)
ELSE ISNULL(T2.Total,0)/ISNULL(T1.Total,0)
END AS Total
FROM TB_1 AS T1
FULL JOIN TB_2 AS T2 ON T1.Month = T2.Month
I have used FULL JOIN to catch all dates from both tables. I have checked for all NULL values and replaced the NULLs by divisible values.

For matching months only, use this -
select TB_1.month as month
,TB_3.total / nullif(TB_1.total,0) as total
from TB_1
join TB_3
on TB_3.month = TB_1.month
order by month
If you wish to also display results for nonmatching months, use this -
select coalesce(TB_1.month,TB_3.month) as month
,TB_3.total / nullif(TB_1.total,0) as total
from TB_1
full join TB_3
on TB_3.month = TB_1.month
order by month
nullif(X,0) is a clean way to express-
Return X unless it is equal to 0, where in that case return a NULL
If the total column are of integer type, replace TB_3.total with TB_3.total::numeric(12,2) (or other precision as you like)

Related

wants to pick most closest record in group of records in single table which input criteria

we have a table and there is possibility that one record can have multiple copies means same record can exist in table with multiple entries but their criteria will be different criteria is decided using three main parameters.income,score,no_months.these columns are integer.and we are grouping them by giving unique code to same records profile.
if one input is eligible for multiple profiles then we need to pick which is most matching to criteria.
Sample Data.
id
name
income
score
no_months
group_code
22
abc
1000
500
6
abccode
23
abc
900
600
12
abccode
24
bca
1000
600
12
bcacode
Desired Results
id
name
income
score
no_months
group_code
23
abc
900
600
12
abccode
24
bca
1000
600
12
bcacode
Note: id 23 row has 2 columns which values are greater than id 22 row that is why id 23 was picked although id 23 has less income
Only those records should be display which columns have more count of greater values than other row if group_code is same.
I have tried using multiple order by with cte as more columns needs to display like image city etc. but its not working
Select a single row for the Name or a winner of multiple rows. Winner is one with max score of wins when compared to others in a triangle join. Provided 2 rows has the same criteria, a row with the lesser id wins.
select *
from tbl t
where id in (
-- winners
select winid
from tbl t1
join tbl t2 on t1.name = t2.name and t1.id < t2.id
join lateral (
select case when sign(t1.income - t2.income) + sign(t1.score - t2.score) + sign(t1.no_months - t2.no_months) >= 0
then t1.id else t2.id end winid
) w on 1=1
group by winid
order by count(*) desc
limit 1)
or not exists(select 1 from tbl t3 where t3.name = t.name and t3.id <> t.id)

sql sum sales between date

The image explains everything. My aim is to the last table using sql.
I will explain the logic with an example.
Table 1 shows the expected sales. For instance, article 22 should be sold only between 1 janv and 4 jan. To make it simple we assume that shops are open every day.
Table 2 shows the daily sales for each article. For instance article was sold 1 janv 2 janv 3 janv 4 janv. However, for article 22 4 janv is not in the range [1 janv to 3 janv]. Thus to get the sum of sales of article 22, we should omit the 4 jan. Therefore the calculation for article 22 is 2+4+5=11.
DataType
Table 1
artNo: int
from: date
planned_to: date
Table 2
artNo: int
day: date
sales: float
Something like this:
SELECT
t1.artNo
, t1.[from]
, t1.planned_to
, SUM(t2.sales) total
FROM
table1 t1
JOIN table2 t2 ON
t1.artNo = t2.artNo
AND t2.day >= t1.[from]
AND t2.day <= t1.planned_to
GROUP BY
t1.artNo
, t1.[from]
, t1.planned_to
SELECT t1.artNO
,t1.
,t1.planned_to
,SUM(sales) as Total
FROM table1 t1
INNER JOIN table2 t2 ON t1.artNo = t2.artNo
GROUP BY t1.artNO
,t1.
,t1.planned_to

SQL query Splitting a column into Multiple rows divide by percentage

How to get percentage of a column and then inserting it as rows
Col1 item TotalAmount**
1 ABC 5558767.82
2 ABC 4747605.5
3 ABC 667377.69
4 ABC 3844204
6 CTB 100
7 CTB 500.52
I need to create a new column percentage for each item which is I have done as :-
Select item, (totalAmount/select sum(totalAmount) from table1) as Percentage
From table1
Group by item
Col1 item TotalAmount percentage
1 ABC 5558767.82 38
2 ABC 4747605.5 32
3 ABC 667377.69 5
4 ABC 3844204 26
6 CTB 100 17
7 CTB 500.52 83
Now, the complex part I have to calculate another amount by multiplying this percentage to an amount from another table say table2
ii) update the Total amount column by spilt the total amount column of table 1 into 2 rows – 1st row of the new Calculate PledgeAmount and 2nd row – (totalAmount – PledgeAmount)
*Select t1.percentage * t2.new amount as [PledgeAmount]
From table 1 join table2 where t1.item=t2.item*
. e.g. for col1 Amount of 5558767.82 will split into two rows.
Final Result sample for :-
Col1 item TotalAmount Type
1 ABC 363700.00 Pledge
1 ABC 5195067.82 Unpledge
....
I am using Temporary table to do calculations.
One of the way I think is to calculate the Pledged and Unpledged amount as new column and Pivot it but its huge table with hundreds of columns it will not perform fast.
Any other efficient way?
You can use a windowing function to solve this problem -- first in a sub-query calculate the total and then in the main query the percent:
Select *, (totalAmount/total_for_item)*100 as percent_of_total
from (
SELECT t.*,
SUM(totalAmount) OVER (PARTITION BY item) as total_for_item
FROM table t
) sub
First, let's get the total amount per item:
SELECT item, SUM( totalAmount ) as sumTotal
INTO #totalperitem
FROM table1
GROUP BY item
Now it's easy to get to the percentages:
SELECT t1.Col1,
t1.item,
t1.totalAmount,
t1.totalAmount/tpi.sumTotal*100 AS percentage
FROM table1 t1
INNER JOIN #totalperitem tpi on ...
Tricky part: Separate rows with/without match in table2. Can be done with a WHERE NOT EXISTS, or, my preference, with a single outer join:
SELECT t1.item,
CASE WHEN tpledged.item IS NULL
THEN "Unpledged"
ELSE "Pledged"
END,
SUM( t1.totalAmount ) AS amount
FROM table1 t1
LEFT OUTER JOIN table2 tpledged ON t1. ... = tpledged. ...
GROUP BY t1.item,
CASE WHEN tpledged.item IS NULL
THEN "Unpledged"
ELSE "Pledged"
END
The basic trick is to create an artificial column from the presence/absence of records in table2 and to also group by that artificial column.

SQL return a default value if a row is not found [PostgreSQL]

I'm wondering if it was doable (in one query if possible) to make the query return a default value if a row is missing ? For example takes these 2 tables and given my query takes 2 parameter (place_id and user_id)
T1
place_id / tag_id
1 2
1 3
1 4
2 4
3 2
4 5
T2
user_id / tag_id / count
100 2 1
100 3 20
200 4 30
200 2 2
300 5 22
As you see, the pair user/tag (100,4) is missing. What I would like to archive is a query that will return me these 3 results
tag_id / count
2 1
3 20
4 0
I know that i can do this with something like this but it doesn't really match the final result as it only works if i know in advance the tag_id... and obviously only return 1 row..:
SELECT T1.tag_id, T2.count
from T1 t1
left join T2 t2 on t1.tagId=t2.tag_id
where t1.place_id=1
UNION ALL
select tag_id,0
from T1
where not exist (select 1 from T2 where user_id=100 and tag_id=4)
and tag_id=4;
EDIT: My question was not complete and had missing cases
here is an example (curtesy of #a_horse_with_no_name) http://sqlfiddle.com/#!12/67042/4
Thank you!
The outer join will already take care of what you want.
As t1 is the "left table" of the join, all rows from t1 will be returned. Columns from the "right table" (t2 in your example) will then have a null value. So you only need to convert that null to a 0:
select t1.tag_id, coalesce(t2.cnt, 0)
from T1 t1
left join T2 t2 on t1.tag_Id=t2.tag_id
and t1.place_id = 1;
SQLFiddle example: http://sqlfiddle.com/#!12/ed7bf/1
Unrelated but:
Using count as a column name is a really bad idea, because it will require you to always enclose the column name in double quotes: t2."count" because it is a reserved word. Plus it doesn't really document the purpose of the column. You should find a better name for that.

SELECT Query merge / join two tables in PostgreSQL

If there are two tables as mentioned below:
Table 1
day acount
1998-03-01 8
1998-03-04 9
1998-03-05 10
1998-03-09 8
Table 2
day bcount
1998-03-02 9
1998-03-03 7
1998-03-05 4
1998-03-06 3
Can a select query return the data in ascending order in the format below?
Result
day acount bcount
1998-03-01 8 0
1998-03-02 0 9
1998-03-03 0 7
1998-03-04 9 0
1998-03-05 10 4
1998-03-06 3 0
1998-03-09 8 0
I would suggest using a FULL OUTER JOIN to join the tables on the day column to get the result:
select coalesce(t1.day, t2.day) "day",
coalesce(t1.acount, 0) acount,
coalesce(t2.bcount, 0) bcount
from table1 t1
full outer join table2 t2
on t1.day = t2.day;
See SQL Fiddle with Demo. The COALESCE function will return the first non-null result, so this can be used to get the day values in the same column and then replace the nulls in the acount and bcount columns.
#bluefeet's query is the way to go. Only adding some syntactical sugar and corrective:
SELECT day
, coalesce(t1.acount, 0) AS acount
, coalesce(t2.bcount, 0) AS bcount
FROM table1 t1
FULL JOIN table2 t2 USING (day)
SQL Fiddle.
If you use the shorter USING clause for the JOIN condition (possible in this case), you also don't need coalesce(t1.day, t2.day), since this is exactly what day without table qualification resolves to after being listed in the USING clause.
While it is ok to skip the key word AS for table aliases, you should never skip it for column aliases - as documented in the manual in a separate paragraph Omitting the AS Key Word:
In FROM items, both the standard and PostgreSQL allow AS to be omitted
before an alias that is an unreserved keyword. But this is impractical
for output column names, because of syntactic ambiguities.