Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to alias selected columns in swift 2 ? #225

Open
huynhphan89 opened this issue Sep 22, 2015 · 8 comments · May be fixed by #1081
Open

How to alias selected columns in swift 2 ? #225

huynhphan89 opened this issue Sep 22, 2015 · 8 comments · May be fixed by #1081

Comments

@huynhphan89
Copy link
Contributor

On branch swift_2.0, alias func was removed in Expression.swift. I dont see any document about the new way to alias columns.

Thanks.

@stephencelis
Copy link
Owner

Aliasing functionality has been limited to tables during the rewrite, where the functionality is required for joins to work. Aliasing column/expressions doesn't seem to help in our expression layer, although I may have missed a use case. Would you please provide your use case?

@shnhrrsn
Copy link

My use case: I'm selecting all columns in table a, joining table b and selecting just one column from table b that happens to share the name of a column in table a.

If I want to access the that column in table b, it means all of my existing models/queries that reference the column of the same name in table a needs to be updated to support namespacing for just this one scenario.

If I were able to select the column in table b aliased to a different name, all of my existing code would work without modification. Essentially I'd like the ability to build this query: SELECT a.*, b.name as otherName FROM a JOIN b ...

@stephencelis
Copy link
Owner

My experimentation showed that these aliases are actually meaningless outside of the SQLite console. You should be able do do this, though:

let a = Table("a")
let b = Table("b")

for row in db.prepare(a.join(b, on: condition)) {
    let aName = row[a[name]]
    let bName = row[b[name]]
}

It doesn't limit table b to just select the name, but that appears to be a bug that needs to be fixed (#249).

@shnhrrsn
Copy link

So what I'm actually doing is a little closer to this:

class Model {
   let name: String

   init(row: Row) {
      self.name = row[name]
   }
}

let a = Table("a")
let b = Table("b")

for row in db.prepare(a.join(b, on: condition)) {
   let model = Model(row)
   // Some how use b[name]
}

I initially tried to just update model to do self.name = row[table[name]] however queries that weren't joining were failing saying the column didn't exist:

fatal error: no such column '"a"."name"' in columns: [""name"", ... ]

If this is supposed to work, than I suppose that solution would be ok, but it would be easier if I could do something along the lines of:

let a = Table("a")
let b = Table("b")
let otherName = b[name].alias("otherName")

for row in db.prepare(a.select(a[*], otherName).join(b, on: condition)) {
    let model = Model(row)
    let bName = row[otherName]
}

This would allow me to isolate this specific bit of code to where I need it, and allow everything else to remain as it is for when namespacing isn't necessary.

@mySelfSystem
Copy link

My use case is providing query results to other iOS Apps via an External API. There is a person table and a measurement table. There are many measurements for any one person, and the column person_oid joins them.

For one particular query to the external Apps, I need to provide for each person the quantity of measurements associated with that person (along with the other columns of a person record). Since this is an external API and some external App that I did not write is getting the results, I want to provide that count with a nice easily understood alias column name rather some default column name including the function.

My SQL statement that works quite well on Android SQLite and a server-based mySQL:
SELECT person.*,COUNT(measurement.person_oid) AS usage_measurements_qty FROM person LEFT JOIN measurement ON (person.person_oid = measurement.person_oid) GROUP BY person.person_oid

I can just about build the equivalent query in SQLite.swift, except for the alias.

let personTbl = Table("person")
let measureTbl = Table("measurement")
let PERSON_OID = Expression<Int64>("person_oid")
let query = personTbl.select(personTbl[*],measureTbl[PERSON_OID].count)
    .join(.LeftOuter, measureTbl, on:personTbl[PERSON_OID] == measureTbl[PERSON_OID])
     .group(personTbl[PERSON_OID])

Of course what I would like is the ability to do something like:
measureTbl[PERSON_OID].count.alias("usage_measurements_qty")

Looking at the Expression.swift file, in extension ExpressionType, it seems like a simple addition to the source code accomplishes this:

extension ExpressionType {

    public var expression: Expression<Void> {
        return Expression(template, bindings)
    }

    public var asc: Expressible {
        return " ".join([self, Expression<Void>(literal: "ASC")])
    }

    public var desc: Expressible {
        return " ".join([self, Expression<Void>(literal: "DESC")])
    }

    // NOTE: MODIFICATION TO BASELINE:  added support for column aliasing, e.g.: "SELECT column AS alias ... FROM ..."
    public func alias(name:String) -> Expressible {
        return " ".join([self, Expression<Void>(literal: "AS \(name)")])
    }
}

And indeed in a fork of the SQLite.swift source code that I'm using in developing my iOS App, I added said 4 lines of code, and it works properly.

let personTbl = Table("person")
let measureTbl = Table("measurement")
let PERSON_OID = Expression<Int64>("person_oid")
let query = personTbl.select(personTbl[*],measureTbl[PERSON_OID].count.alias("usage_measurements_qty"))
    .join(.LeftOuter, measureTbl, on:personTbl[PERSON_OID] == measureTbl[PERSON_OID])
     .group(personTbl[PERSON_OID])
print(query.asSQL())

resulted in:
SELECT \"person\".*, count(\"measurement\".\"person_hash_oid\") AS usage_qty_measurements FROM \"person\" LEFT OUTER JOIN \"measurement\" ON (\"person\".\"person_hash_oid\" = \"measurement\".\"person_hash_oid\") GROUP BY \"person\".\"person_hash_oid\

@gverdouw
Copy link

Another place this is useful is when trying to use Codable for the result -- trying to get a CodingKeys case to satisfy the generated Table.Column name is very painful (maybe impossible?). I ended up just creating the objects manually instead

@Devangbhatt93
Copy link

Devangbhatt93 commented Jan 9, 2019

_extension ExpressionType {

public var expression: Expression<Void> {
    return Expression(template, bindings)
}

public var asc: Expressible {
    return " ".join([self, Expression<Void>(literal: "ASC")])
}

public var desc: Expressible {
    return " ".join([self, Expression<Void>(literal: "DESC")])
}

// NOTE: MODIFICATION TO BASELINE:  added support for column aliasing, e.g.: "SELECT column AS alias ... FROM ..."
public func alias(name:String) -> Expressible {
    return " ".join([self, Expression<Void>(literal: "AS \(name)")])
}

}_

This is not working for me.

Error: join' is inaccessible due to 'internal' protection level

@adamwulf
Copy link
Contributor

adamwulf commented Sep 1, 2021

any movement on this? I have the same issue as #225 (comment) and would like to provide specific column names to aggregate columns

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants