Combination of SQL Rows - sql

I have a table with following structure and i want to populate data to another table from this table with table structure table2
Table1
╔═══════╦═══════╗
║ State ║ City ║
╠═══════╬═══════╣
║ A ║ AA ║
║ B ║ BB ║
║ C ║ CC ║
║ D ║ DD ║
╚═══════╩═══════╝
Table2
╔═══════════╦═════════╦═══════════╦═══════════╗
║ SrcState1 ║ SrcCity ║ DestState ║ DestCity ║
╠═══════════╬═════════╬═══════════╬═══════════╣
║ A ║ AA ║ B ║ BB ║
║ A ║ AA ║ C ║ CC ║
║ A ║ AA ║ D ║ DD ║
║ ║ ║ ║ ║
║ B ║ BB ║ A ║ AA ║
║ B ║ BB ║ C ║ CC ║
║ B ║ BB ║ D ║ DD ║
║ ║ ║ ║ ║
║ C ║ CC ║ A ║ AA ║
║ C ║ CC ║ B ║ BB ║
║ C ║ CC ║ D ║ DD ║
║ D ║ DD ║ A ║ AA ║
║ D ║ DD ║ B ║ BB ║
║ D ║ DD ║ C ║ CC ║
╚═══════════╩═════════╩═══════════╩═══════════╝
EDIT
Actually it should look like this:
╔═══════════╦═════════╦═══════════╦═══════════╗
║ SrcState1 ║ SrcCity ║ DestState ║ DestCity ║
╠═══════════╬═════════╬═══════════╬═══════════╣
║ A ║ AA ║ B ║ BB ║
║ A ║ AA ║ C ║ CC ║
║ A ║ AA ║ D ║ DD ║
║ ║ ║ ║ ║
║ B ║ BB ║ C ║ CC ║
║ B ║ BB ║ D ║ DD ║
║ ║ ║ ║ ║
║ C ║ CC ║ D ║ DD ║
╚═══════════╩═════════╩═══════════╩═══════════╝

I think you need a query like this:
SELECT *
FROM Table1 t1
INNER JOIN
Table1 t2 ON t1.[state] < t2.[state];
or for a better solution:
;WITH t AS(
SELECT *,
ROW_NUMBER() OVER (ORDER BY [State]) As rn
FROM Table1)
SELECT *
FROM t t1
INNER JOIN
t t2 ON t1.rn < t2.rn;

You can use CROSS JOIN to generate Cartesian Product tab x tab and exclude in WHERE tab.state <> tab.state:
This solution works for original question.
SqlFiddleDemo
CREATE TABLE tab(state NVARCHAR(10), City NVARCHAR(10));
INSERT INTO tab(state, city)
VALUES ('A', 'AA'), ('B', 'BB'), ('C', 'CC'), ('D', 'DD');
SELECT
a.state
,a.city
,b.state
,b.city
FROM tab a
CROSS JOIN tab b
WHERE a.state <> b.state
ORDER BY a.state, a.city, b.state, b.city
For future state your question clearly if you want to get something like below use shA.t Solution:
╔═══════════╦═════════╦═══════════╦═══════════╗
║ SrcState1 ║ SrcCity ║ DestState ║ DestCity ║
╠═══════════╬═════════╬═══════════╬═══════════╣
║ A ║ AA ║ B ║ BB ║
║ A ║ AA ║ C ║ CC ║
║ A ║ AA ║ D ║ DD ║
║ ║ ║ ║ ║
║ B ║ BB ║ C ║ CC ║
║ B ║ BB ║ D ║ DD ║
║ ║ ║ ║ ║
║ C ║ CC ║ D ║ DD ║
╚═══════════╩═════════╩═══════════╩═══════════╝

Related

Multiple Full Joins On a User Table in a Single Query

I have a schema of a database where we have a a user table and several fact tables.
The schema is goes something like this:
╔════════════╗
║ USERS ║
╠════════════╣
║ sales_id ║ PK
║ traveler_id║ PK
╚════════════╝
╔════════════╗
║ Sales ║
╠════════════╣
║ sales_id ║ --> FK to User sales_id PK
║ date ║
║ metric_1 ║
║ metric_2 ║
╚════════════╝
╔════════════╗
║ Travels ║
╠════════════╣
║ traveler_id║ --> FK to User traveler_id PK
║ date ║
║ metric_3 ║
║ metric_4 ║
╚════════════╝
I'm trying to join them as a single fact table to get all the metrics and their dates in a inqle query. It would return something like below:
╔════════════╦══════════════╦══════════╦══════════╦══════════╦══════════╦══════════╗
║ sales_id ║ traveler_id ║ date ║ metric_1 ║ metric_2 ║ metric_3 ║ metric_4 ║
╠════════════╬══════════════╬══════════╬══════════╬══════════╬══════════╬══════════╣
║ 1 ║ A ║ Jan ║ x1 ║ a1 ║ null ║ null ║
║ 1 ║ A ║ Feb ║ x2 ║ a2 ║ null ║ null ║
║ 1 ║ A ║ Jan ║ x3 ║ a3 ║ b1 ║ null ║
║ 2 ║ B ║ Mar ║ x4 ║ a4 ║ null ║ c1 ║
╚════════════╩══════════════╩══════════╩══════════╩══════════╩══════════╩══════════╝
Here is the sql I wrote:
select
coalesce(s.date, t.date) as date,
s.sales_id,
t.traveler_id,
max(coalesce(s.metric_1, 0)) as metric_1,
max(coalesce(s.metric_2, 0)) as metric_2,
max(coalesce(t.metric_3, 0)) as metric_3,
max(coalesce(t.metric_4, 0)) as metric_4,
from users as u
full join sales as s on (u.sales_id = s.sales_id)
full join travels as t on (u.traveler_id = t.traveler_id)
group by 1, 2, 3
However, my joining logic ends up returning the same values for the rows that are as null.
╔════════════╦══════════════╦══════════╦══════════╦══════════╦══════════╦══════════╗
║ sales_id ║ traveler_id ║ date ║ metric_1 ║ metric_2 ║ metric_3 ║ metric_4 ║
╠════════════╬══════════════╬══════════╬══════════╬══════════╬══════════╬══════════╣
║ 1 ║ A ║ Jan ║ x1 ║ a1 ║ b1 ║ null ║
║ 1 ║ A ║ Feb ║ x2 ║ a2 ║ b1 ║ null ║
║ 1 ║ A ║ Jan ║ x3 ║ a3 ║ b1 ║ null ║
║ 2 ║ B ║ Mar ║ x4 ║ a4 ║ null ║ null ║
╚════════════╩══════════════╩══════════╩══════════╩══════════╩══════════╩══════════╝
My suspicion is that it's due to the second full join. I would assume I could break these down into two other joins, and match their id, but I'm having a hard time trying to understand how to incorporate the dates, properly.
select
coalesce(s.date, t.date) as date,
s.sales_id,
t.traveler_id,
max(coalesce(s.metric_1, 0)) as metric_1,
max(coalesce(s.metric_2, 0)) as metric_2,
max(coalesce(t.metric_3, 0)) as metric_3,
max(coalesce(t.metric_4, 0)) as metric_4
from users as u
left join sales as s on (u.sales_id = s.sales_id and s.date = coalesce(s.date, t.date))
left join travels as t on (u.traveler_id = t.traveler_id and t.date = coalesce(s.date, t.date))
group by 1, 2, 3
This is what the table looks like:
╔════════════╦══════════════╦══════════╦══════════╦══════════╦══════════╦══════════╗
║ sales_id ║ traveler_id ║ date ║ metric_1 ║ metric_2 ║ metric_3 ║ metric_4 ║
╠════════════╬══════════════╬══════════╬══════════╬══════════╬══════════╬══════════╣
║ 1 ║ A ║ Jan ║ x1 ║ a1 ║ b1 ║ null ║
║ 1 ║ A ║ Feb ║ x2 ║ a2 ║ null ║ null ║
║ 1 ║ A ║ Jan ║ x3 ║ a3 ║ b1 ║ null ║
║ 2 ║ B ║ Mar ║ x4 ║ a4 ║ null ║ c1 ║
╚════════════╩══════════════╩══════════╩══════════╩══════════╩══════════╩══════════╝

How to remove count values "0" from result table?

I'm trying to write a query that returns a table with columns name and numberOfClasses. This table includes the name of all students and the amount of classes the student follows. I use the following database tables:
╔══════════════╦═══════════╦══════════╗
║ TakesClasses ║ ║ ║
╠══════════════╬═══════════╬══════════╣
║ id ║ person_id ║ class_id ║
║ 99 ║ 1 ║ 40 ║
║ 98 ║ 1 ║ 41 ║
║ 97 ║ 1 ║ 42 ║
║ 96 ║ 1 ║ 43 ║
║ 95 ║ 2 ║ 44 ║
║ 94 ║ 2 ║ 45 ║
║ 93 ║ 2 ║ 46 ║
╚══════════════╩═══════════╩══════════╝
╔═════════╦═══════╦══╗
║ Persons ║ ║ ║
╠═════════╬═══════╬══╣
║ id ║ name ║ ║
║ 1 ║ Bart ║ ║
║ 2 ║ David ║ ║
║ 3 ║ Dani ║ ║
║ 4 ║ Erik ║ ║
╚═════════╩═══════╩══╝
I used the following query:
SELECT
name,
COUNT(T.person_id) AS numberOfClasses
FROM
Persons P
LEFT OUTER JOIN
TakesClasses T ON P.id = T.person_id
GROUP BY
P.id, P.name
And this is the output:
╔═══════╦═════════════════╗
║ name ║ numberOfClasses ║
╠═══════╬═════════════════╣
║ Bart ║ 4 ║
║ Dani ║ 3 ║
║ David ║ 0 ║
║ Erik ║ 0 ║
╚═══════╩═════════════════╝
How can I remove the entries with 0 from my the results table?
Thanks for the help in advance!
Just use JOIN instead of LEFT JOIN
select name, count(T.person_id) as amountOfClasses
from Persons P join
TakesClasses T
on P.id = T.person_id
group by P.id, P.name
If you want to filter on aggregated data like what comes out of GROUP BY you can use the HAVING clause
SELECT name,COUNT(T.person_id) as amountOfClasses
FROM Persons P LEFT OUTER JOIN TakesClasses T
on P.id = T.person_id
GROUP BY P.id, P.name
HAVING COUNT(T.person_id) > 0;
sqlFiddle: http://sqlfiddle.com/#!9/1108c5/8

Sorting and Number results based in order, using multiple columns "order by" criteria

all
I've been trying to do, with data following the structure:
╔══════════════╦═══════════╦══╗
║ Alphabetical ║ Numerical ║ ║
╠══════════════╬═══════════╬══╣
║ A ║ 15 ║ ║
║ A ║ 30 ║ ║
║ E ║ 100 ║ ║
║ C ║ 45 ║ ║
║ F ║ 25 ║ ║
║ C ║ 65 ║ ║
║ B ║ 25 ║ ║
║ F ║ 35 ║ ║
║ C ║ 100 ║ ║
║ A ║ 10 ║ ║
║ C ║ 20 ║ ║
║ B ║ 5 ║ ║
║ E ║ 10 ║ ║
║ F ║ 85 ║ ║
║ D ║ 30 ║ ║
║ F ║ 1 ║ ║
╚══════════════╩═══════════╩══╝
To get the following:
╔══════════════╦══════╦═════════╗
║ Alphabetical ║ Rank ║ Numeric ║
╠══════════════╬══════╬═════════╣
║ A ║ 1 ║ 30 ║
║ A ║ 2 ║ 15 ║
║ A ║ 3 ║ 10 ║
║ B ║ 1 ║ 25 ║
║ B ║ 2 ║ 5 ║
║ C ║ 1 ║ 100 ║
║ C ║ 2 ║ 65 ║
║ C ║ 3 ║ 45 ║
║ C ║ 4 ║ 20 ║
║ D ║ 1 ║ 30 ║
║ E ║ 1 ║ 100 ║
║ E ║ 2 ║ 10 ║
║ F ║ 1 ║ 85 ║
║ F ║ 2 ║ 35 ║
║ F ║ 3 ║ 25 ║
║ F ║ 4 ║ 1 ║
╚══════════════╩══════╩═════════╝
Basically, to order the alphabetical field in ascending order, the numerical field in descending order and get the order or rank by using the order used for the numerical field, grouped by the alphabetical field.
I have only achieved it if I limit it to one specific value in the Alphabetical column, by using something like:
select ordered_src.*, ROWNUM Rank from (select src.* from Source src where alphabetical = 'A' order by Numeric desc) ordered_src;
But I have no idea how to get the result shown above. Any idea? Also, is there any alternative that will work also in mysql/mssql/etc?
Thanks!
Use row_number():
select s.*,
row_number() over (partition by alphabetical order by numerical desc) as rank
from source s
order by alphabetical, rank;

Multiple joins on same table?

I have two table:
tbl_EmploymentSegmentEM:
╔══════╦═════════════╦════════════╦═══════════════╦═══════════════════════════════╦════════════╦═════════════╦══════════════════════════╦════════════════╗
║ SrNo ║ CIBILTuefID ║ Prospectno ║ ApplicantType ║ ApplicantName ║ SegmentTag ║ AccountType ║ DateReportedandCertified ║ OccupationCode ║
╠══════╬═════════════╬════════════╬═══════════════╬═══════════════════════════════╬════════════╬═════════════╬══════════════════════════╬════════════════╣
║ 1 ║ 1 ║ 718580 ║ APPLICANT ║ RAJKUMAR GIRISHCHANDRA PANDEY ║ E01 ║ 10 ║ 31122014 ║ 02 ║
║ 2 ║ 4 ║ 718638 ║ APPLICANT ║ Anil Kumar Aggarwal ║ E01 ║ 10 ║ 31122014 ║ 01 ║
╚══════╩═════════════╩════════════╩═══════════════╩═══════════════════════════════╩════════════╩═════════════╩══════════════════════════╩════════════════╝
tbl_CIBILFieldDescription:
╔════════╦══════════╦══════════════════════════════╦═══════╦═════════════════════════════╗
║ Header ║ FieldTag ║ FieldName ║ Value ║ ValueDescription ║
╠════════╬══════════╬══════════════════════════════╬═══════╬═════════════════════════════╣
║ PT ║ 03 ║ TelephoneType ║ 03 ║ Office Phone ║
║ EM ║ 03 ║ OccupationCode ║ 01 ║ Salaried ║
║ EM ║ 03 ║ OccupationCode ║ 02 ║ Self Employed Professional. ║
║ EM ║ 03 ║ OccupationCode ║ 03 ║ Self Employed ║
║ EM ║ 03 ║ OccupationCode ║ 04 ║ Others ║
║ EM ║ 05 ║ NetGrossIncomeIndicator ║ G ║ Gross Income ║
║ EM ║ 05 ║ NetGrossIncomeIndicator ║ N ║ Net Income ║
║ EM ║ 06 ║ MonthlyAnnualIncomeIndicator ║ M ║ Net Monthly ║
║ EM ║ 06 ║ MonthlyAnnualIncomeIndicator ║ A ║ Net Annual ║
║ SC ║ 01 ║ ScoreCardName ║ 01 ║ CIBILTUSCR ║
╚════════╩══════════╩══════════════════════════════╩═══════╩═════════════════════════════╝
I am trying to get Account Type and Occupation code description from tbl_CIBILFieldDescription for the corresponding values.
I tried this :
SELECT DISTINCT CIBILTuefID,
Prospectno,
ApplicantType,
ApplicantName,
SegmentTag,
AccountType,
DateReportedandCertified,
OccupationCode,
mst.ValueDescription AS OccupationCodeDesc,
Income,
NetGrossIncomeIndicator,
mst.ValueDescription AS NetGrossIncomeIndicatorDesc,
MonthlyAnnualIncomeIndicator,
DateofEntryforErrorCode,
ErrorCode,
DateofEntryforCIBILRemarksCode,
CIBILRemarksCode,
DateofEntryforErrorDisputeRemarksCode,
ErrorDisputeRemarksCode1,
ErrorDisputeRemarksCode2,
MkrId,
MkdDt
FROM tbl_EmploymentSegmentEM EM
INNER JOIN tbl_CIBILFieldDescription mst
ON 1 = 1
WHERE mst.Header = 'EM'
AND mst.FieldName = 'OccupationCode'
AND mst.Value = EM.OccupationCode
And it seems to work ok for OccupationCode but what if I want both OccupationCode and AccountType from the same query? What is the best way to do this?
You can join your table multiple times using LEFT JOIN:
SELECT DISTINCT cibiltuefid,
prospectno,
applicanttype,
applicantname,
segmenttag,
accounttype,
datereportedandcertified,
occupationcode,
mst.valuedescription AS OccupationCodeDesc,
income,
netgrossincomeindicator,
mst1.valuedescription AS NetGrossIncomeIndicatorDesc,
monthlyannualincomeindicator,
dateofentryforerrorcode,
errorcode,
dateofentryforcibilremarkscode,
cibilremarkscode,
dateofentryforerrordisputeremarkscode,
errordisputeremarkscode1,
errordisputeremarkscode2,
mkrid,
mkddt
,mst.ValueDescription AS Occupation
,mst1.ValueDescription AS Account
FROM tbl_employmentsegmentem EM
LEFT JOIN tbl_cibilfielddescription mst
ON mst.fieldname = 'OccupationCode'
AND mst.value = EM.occupationcode
AND mst.header = 'EM'
LEFT JOIN tbl_cibilfielddescription mst1
ON mst1.fieldname = 'AccountType'
AND mst1.value = EM.accounttype
AND mst1.header = 'EM'

Matching data from two tables with unequal number of rows

I have 2 tables, and I am trying to match up the data but all the answers have suggested right joins or full joins, which are not available on SQLite.
Table 1:
╔═════════╦═════════╦══════╗
║ Company ║ Product ║ Cost ║
╠═════════╬═════════╬══════╣
║ A ║ abc ║ 100 ║
║ B ║ abc ║ 150 ║
║ F ║ xyz ║ 250 ║
║ G ║ xyz ║ 300 ║
╚═════════╩═════════╩══════╝
However I have a list of more companies (with same products)
Table 2:
╔═════════╦═════════╗
║ Product ║ Company ║
╠═════════╬═════════╣
║ abc ║ A ║
║ abc ║ B ║
║ abc ║ C ║
║ abc ║ D ║
║ abc ║ E ║
║ abc ║ F ║
║ abc ║ G ║
║ xyz ║ A ║
║ xyz ║ B ║
║ xyz ║ C ║
║ xyz ║ D ║
║ xyz ║ E ║
║ xyz ║ F ║
║ xyz ║ G ║
╚═════════╩═════════╝
How do I match them up so they look like this?
Table 3:
╔═════════╦═════════╦══════╗
║ Product ║ Company ║ Cost ║
╠═════════╬═════════╬══════╣
║ abc ║ A ║ 100 ║
║ abc ║ B ║ 150 ║
║ abc ║ C ║ null ║
║ abc ║ D ║ null ║
║ abc ║ E ║ null ║
║ abc ║ F ║ null ║
║ abc ║ G ║ null ║
║ xyz ║ A ║ null ║
║ xyz ║ B ║ null ║
║ xyz ║ C ║ null ║
║ xyz ║ D ║ null ║
║ xyz ║ E ║ null ║
║ xyz ║ F ║ 250 ║
║ xyz ║ G ║ 300 ║
╚═════════╩═════════╩══════╝
When I use this code,
SELECT Company, t.Product, Cost
FROM table1 as t INNER JOIN table2 as f ON t.product = f.product
WHERE t.company = f.company
it only returns [Company] with an associated [Product] and [Cost], but does not return [Company] with null values.
When I use
SELECT Company, t.Product, Cost
FROM table1 as t INNER JOIN table2 as f ON t.company = f.company
then my output looks like
╔═══════════╦═══════════╦═════════╗
║ t.Company ║ f.Company ║ Product ║
╠═══════════╬═══════════╬═════════╣
║ A ║ A ║ abc ║
║ B ║ A ║ abc ║
║ F ║ A ║ abc ║
║ G ║ A ║ abc ║
║ A ║ B ║ abc ║
║ B ║ B ║ abc ║
║ F ║ B ║ abc ║
║ G ║ B ║ abc ║
║ A ║ C ║ abc ║
║ B ║ C ║ abc ║
║ F ║ C ║ abc ║
║ G ║ C ║ abc ║
╚═══════════╩═══════════╩═════════╝
Any help will be much appreciated. Thank you!
SQLite does support LEFT OUTER JOIN, which should do the job just fine:
select two.product, two.company, one.cost from two
left outer join one on
((one.company = two.company) and (one.product = two.product));
(where two is your "table 2" and one is your "table 1")
Running this in SQLite with the above data:
abc|A|100
abc|B|150
abc|C|
abc|D|
abc|E|
abc|F|
abc|G|
xyz|A|
xyz|B|
xyz|C|
xyz|D|
xyz|E|
xyz|F|250
xyz|G|300