What does "s." and "n" mean/do in this mysql statement? - php

I'm currently working on a project that requires me look at someone elses code, i'm still new to some of this stuff and there is something that I dont quite understand so was hoping someone could shed some light on what the code is actually doing or what it means?
Here is the statement in question:
select s.* from $tableA n, $tableB s where
n.id='$send' and
n.status='$status' and
n.field=s.id";
I understand that down to basics this statement is getting all of the fields from tableA and tableB im just unsure what the s. does or what the n does in this statement? are they simply there as identifiers or am I completely wrong in this manner? I am happy to provide more information if it is necessary.

They are called SQL Table Aliases and are basically temporary names which you give to the tables in order to have better readability when you use the table names to specify a column.
In your example
SELECT s.* FROM $tableA n, $tableB s
WHERE n.id='$send'
AND n.status='$status'
AND n.field=s.id ;
is the same as
SELECT $tableB.* FROM $tableA, $tableB
WHERE $tableA.id='$send'
AND $tableA.status = '$status'
AND $tableA.field = $tableB.id ;
but obviously it's easier to read.
The table aliases are even more useful when you join more tables and are absolutely a must when you make self joins.
Syntax note:
You may or you may not use the AS keyword when alias a table.
SELECT table_name AS alias
is the same as
SELECT table_name alias
and although it's longer sometimes it leads to a better readability (for example in a large and messy query the big AS is easier to spot :)

Related

SQL need help to group my results

Hey guy im looking to display some data from my oracle DB. im looking to group it by common data/column but cant figure it out.
$stid = oci_parse($conn, " SELECT REQ.REQSTN_NO, REQ.WO_NO, REQ.COST_CENTRE_CD, REQ.ACCT_PRIME_CD, REQ.ACCT_SUBSDRY_CD, REQ.STOCK_CD
FROM TE.REQSTNREQ
WHERE REQ.DEPT_CD='ISN'");
oci_execute($stid);
while (($row = oci_fetch_array($stid, OCI_BOTH+OCI_RETURN_NULLS)) != false) {
echo $row['COST_CENTRE_CD']."-".$row['ACCT_PRIME_CD']."-".$row['ACCT_SUBSDRY_CD']." ".$row['WO_NO']." ".$row['REQSTN_NO']." ".$row['STOCK_CD']."<br />";
}
Im looking to create an output like this
Ive tried Group BY and SUM/COUNT but i dont know how to structure the code properly any help would be appreciated.
This is not a real database "grouping" -- it is a display issue: you want to group rows with common column values together and print each shared column value only once.
Such display issues are best left to the presentation layer of your application and best left out of the SQL/data model layer.
Nevertheless, here is a technique you can use to group common column values together and to print each value only once, using SQL.
(Since you didn't provide your data in text form, this example uses DBA_OBJECTS to illustrate the technique).
SELECT
-- Order the row_number () partitions the same way the overall query is ordered...
case when row_number() over (partition by object_type order by object_type, owner, object_name) = 1 THEN object_type ELSE NULL END object_type,
case when row_number() over (partition by object_type, owner order by object_type, owner, object_name) = 1 THEN owner ELSE NULL END owner,
object_name,
created, last_ddl_time
FROM dba_objects o
ORDER BY
-- Important to qualify columns in ORDER BY...
o.object_type, o.owner, o.object_name;
The idea is that case statements check to see if this is the first row in a new shared common value and, only if so, to print the column value. Otherwise, it prints NULL.
You would need to use an object-relational database to achieve such a result.
Edited answer:
In MySQL you can use the following function: GROUP_CONCAT:
See reference: https://dev.mysql.com/doc/refman/5.5/en/group-by-functions.html#function_group-concat
I believe there is a similar solution in oracle. You would need to refer to the following question:
Is there any function in oracle similar to group_concat in mysql?

PHP/SQL Query where tables match (wildcard)

Last time you guys were super helpful, let's hope we can also resolve the following challenge that I'm having.
I have 2 tables in the same database and trying to match fields. Here is the query I'm looking for with the table name however I cannot get it to work:
I want to MATCH table "projects" and Column "categorysecond" table "users_profile" and Column "category".
projects.categorysecond might include example; "Roofing,Windows,Landscaping" and users_profile.category might only have EITHER "Roofing" OR "Windows" OR "Landscaping", so I want to pull the results from "projects" if a result from users_profile.category FITS in projects.categorysecond
***Important - I do not have unique identifiers to do a inner join on example ID. The only match should be on the tables listed above, if words(%Wildcard) from one fits the other.
SAMPLE OF MY ATTEMPT
$sql = "SELECT DISTINCT users_profiles.username, projects.id FROM users_profiles, projects WHERE users_profiles.category like '%' + projects.categorysecond + '%'";
Does this make sense? :)
Thank you in advance.
select distinct
up.username
,p.id
from users_profiles as up
join projects as p
on concat(',',p.categorysecond,',') like concat('%,',up.category,',%')
You have a really bad data format. You should not be storing lists of things in a comma-delimited field. The trouble you are having with this query is just one example of the issues. You cannot get such queries to take advantage of indexes or other optimization techniques.
Sometimes, we are stuck with other people's really bad design decisions. MySQL has the function find_in_set() with works in this case:
SELECT DISTINCT up.username, p.id
FROM users_profiles up JOIN
projects p
ON find_in_set(up.category, p.categorysecond) > 0;
Note: If you don't need the DISTINCT, then don't include it. It just incurs a performance penalty.

if else clause in sql, automatic rebuild of indexes

I am in need of a sql construct which gives the following functionality.
select if-expression if status='regular' else else-expression
from table-name ;
This operation will be used very frequently. So, I am considering building an index for this operation.
But, I heard that indexes are not rebuilt after table is being updated. Is there a way we can have automatically rebuild indexes?
Thanks in advance
The translation in SQL of your statement is:
select (case when status = 'regular' then <if-expression> else <else-expression> end)
from tablename;
An index will not help with this query, because you are not limiting the rows in any way. An index can help when you have filters in a where clause, joins, and correlated subqueries (and sometimes I think with group by).
And as MarcB points out in a comment, MySQL (and all other databases) keep indexes up to date for insert, update, and delete operations.
You did not provide a more detailed example.
There are several alternative solutions to your idea, not just the "use-the-index-luke-solution". And depends a lot on your database.
Another alternative could be using "union". In some circumstances could use too much resources, in others, may be the optimal solution, even if using too many records.
SELECT
<if-expression>
FROM
MyTable
WHERE
(MyTable.status = 'regular')
UNION
SELECT
<else-expression>
FROM
MyTable
WHERE
(MyTable.status <> 'regular')
And, in some circumstances, you may also add
SELECT
<if-expression>
FROM
MyTable
WHERE
(MyTable.status = 'regular')
ORDER BY <indexed-fields-used-in-expression>
UNION
SELECT
<else-expression>
FROM
MyTable
WHERE
(MyTable.status <> 'regular')
ORDER BY <indexed-fields-used-in-expression>
Cheers.

Join table, for which the table name has to be grabbed in the same query

This question is not to discuss if the setup of the DB is as it should be, i'm not happy with how it is, but it is how it is and a refactor will not be done by the DBA at this moment.
What i am looking for is a way to join a table, for which i do not in advance know the table name but it is in the table i want to do the join against.
So:
TABEL transactions
trans_id autherizer
001Bar payment_provider_a
001Foo payment_provider_b
TABLE payment_provider_a
trans_id amount
001Bar 50
TABLE payment_provider_b
trans_id amount
001Foo 50
The table names are fictional, but the setup is identical. There is a transaction table, which stores an transaction_id and a payment_provider string name (with a lot of additional data, which is not relevant for the question).
Would there be anyway to get all the data from the transaction table and in that query do directly a join on the payment_provider table, for which we only now what that table can be from the transaction table.
I have tagged it with PHP as well, since i want to make the call with PDO. Whole PHP snippets are not required, but if you insist ;). A push in the right direction for the query it self would be sufficient. I am aware that i am lacking the example of what i have tried. But to be honest i haven't tried that much because i can't really think of something, it's the first time i am in this kind of need for such a query.
Not overly clean, but you can try this:
SELECT * FROM transactions t JOIN
(
SELECT 'payment_provider_a' AS name,* FROM payment_provider_a
UNION
SELECT 'payment_provider_b' AS name,* FROM payment_provider_b
) p ON t.payment_provider = p.name AND t.trans_id=p.trans_id
Note that all payment_provider_x tables must have the same number and types of columns. Otherwise you'll need to select only the fields that are actually common (there are ways around this if needed).

Propel equivalent of "exists"

I am new to Propel and have been reading the documentation. But, I have not found a clear equivalent to the EXISTS and NOT EXISTS constructs from SQL. Linq in .NET, for instance, has Any(). Is there an equivalent to the following in "idiomatic" Propel?
SELECT a.column1, a column2, a.etc
FROM TableA a
WHERE NOT EXISTS (SELECT 1
FROM TableB b
WHERE b.someIdColumn = a.someIdColumn
AND b.aNullableDateColumn IS NULL)
After doing some more digging, I believe I have an answer to my question, or at least as good an answer as is currently available.
What comes after EXISTS or NOT EXISTS is a subquery. While that fact seems obvious, it did not originally occur to me to focus my search for help on subqueries. I found a few resources on the topic. Essentially, the options are to rewrite the query using JOINs (as is the heart of the answer by #Kaltas) or to use Criteria::CUSTOM. I decided I would likely prefer the second option, since it allows me to keep the subquery, potentially helping my database performance.
I did a lot of reading, then, about Criteria::CUSTOM, but the only reading that really helped me was reading the Propel 1.5 source. It's very simple, really. Just put the subquery, verbatim (using the database's table and column names, not Propel's object names) along with EXISTS or NOT EXISTS in the where call, like:
TableAQuery::create()
->where('NOT EXISTS (SELECT 1 FROM TableB WHERE TableA.someIdColumn = TableB.someIdColumn AND TableB.aNullableDateColumn IS NULL)')
->find();
It's that simple. Internally, the where method goes through a few possibilities for interpreting the clause, and finding no matches, it treats the clause as being of Criteria::CUSTOM and inserts it into the SQL query as-is. So, I could not use table aliases, for example.
If I ever have time, maybe I'll work on a more "ORM-ish" way to do this and submit a patch. Someone will probably beat me to it, though.
As in propel 1.6 u now can use Criteria::IN and Criteria::NOT_IN
Example : Select all users that are not in an UserGroup
$users = UserQuery::create()->filterById(UserPerUserGroupQuery::create()->select('user_id')->find(), CRITERIA::NOT_IN)
->orderByUserName()
->find();
I think you could rewrite the query as:
SELECT
a.column1,
a.column2,
a.etc
FROM
TableA a
WHERE
(SELECT
COUNT(*)
FROM
TableB b
WHERE
b.someIdColumn = a.someIdColumn
AND
b.aNullableDateColumn IS NULL
) > 0
which is easily doable in Propel.
Or even cleaner and easier to accomplish in Propel:
SELECT
a.column1,
a.column2,
a.etc
FROM
TableA a
LEFT JOIN
TableB b ON (b.someIdColumn = a.someIdColumn)
WHERE
b.aNullableDateColumn IS NULL
AND
b.primaryKeyColumn IS NOT NULL
Propel 2 can do:
TableAQuery::create()
->useTableBNotExistsQuery()
->filterByNullableDateColumn(null)
->endUse()
->find();
or
$nestedB = TableBQuery::create()
->filterByNullableDateColumn(null)
->where('TableB.someIdColumn = TableA.someIdColumn');
TableAQuery::create()->whereExists(nestedB)->find();

Categories