How to add whole array to one field in database - sql

I have tried everything, array_push, multidimensional array and so on and nothing worked for me.
Following situation:
try {
if (isset($_SESSION['list']) > 0) {
foreach($_SESSION['list'] as $id=> $quantity) {
$sQuery = "SELECT * FROM table WHERE id = '".$id."' ";
$oStmt = $db->prepare($sQuery);
$oStmt->execute();
while($aRow = $oStmt->fetch(PDO::FETCH_ASSOC)) {
$id = $aRow['id'];
$name = $aRow['name'];
$volume = $aRow['volume'];
}
$testar = array(array('name' => $name, 'volume' => $volume, 'quantity' => $quantity));
$sQuery = "INSERT INTO table (array_data, date) VALUES ('$testar', NOW())";
$oStmt = $db->prepare($sQuery);
$oStmt->execute();
print_r($testar);
}
}
else {
echo 'Nothing to add';
}
}
catch(PDOException $e) {
$sMsg = '<p>
Regelnummer: '.$e->getLine().'<br />
Bestand: '.$e->getFile().'<br />
Foutmelding: '.$e->getMessage().'
</p>';
trigger_error($sMsg);
}
when I print_r($testar); I get this:
Array ( [0] => Array ( [name] => test 1 [volume] => 1.50 [quantity] => 4 ) ) Array ( [0] => Array ( [name] => test 2 [volume] => 2.50 [quantity] => 5 ) ) Array ( [0] => Array ( [name] => test 3 [volume] => 2.50 [quantity] => 2 ) )
but when I add it to database I only see: ARRAY.
How is that possible?
What I want is to add the whole Array to one field in database. Is that possible and how can I arrange that?

Usually, a column in an SQL database should have only one value, not an array. If you have multiple values, you should values individually, either as separate columns if they are a set of totally different types of data, or else as a single column on multiple rows of a dependent table if the array is multiple values of the same type of data.
This rule comes from First Normal Form.
But if you really need to store a PHP array in one row, you can convert the PHP array into a string with PHP's serialize() function. This is better than implode() because serialize() preserves hash keys, arrays of arrays, etc.
$testar = array(array('name' => $name, 'volume' => $volume, 'quantity' => $quantity));
$testar_serialized = serialize($testar);
$sQuery = "INSERT INTO table (array_data, date) VALUES (?, NOW())";
$oStmt = $db->prepare($sQuery);
$oStmt->execute( array($testar_serialized) );

I would start looking at the implode function.
Than you can add all the elements in the array to the field in the database, represented as a string.

A few things:
You don't insert an array into an SQL table; you insert the values of it.
Your SQL table should have a "column" for each field (e.g. name, volume, quantity), and will get a "row" for each entry in the outer array.
You should not have a variable reference in your SQL. This is called an “SQL injection vector,” and (due to accident or malice) will eventually wreak havoc upon you.
What you should do where your INSERT is, is:
prepare your SQL statement once:
INSERT INTO table (name, volume, quantity) VALUES (?,?,?);
The ? mark where the SQL drivers will place your values, which you specify later.
This tells the database to get ready to accept (1 or more) inserts in this form, and
shows the database driver (PDO, mysqli, …) where to put the values when you later
call execute
For each row in the array:
call execute with the list of values, e.g. ->execute ($testar->[$i]->['name'], …

Related

getProduct()->getTag() return null, when it should return tags associated to the Product

In my project, we have products that has tag called serviceItem. Those item with that tag when ordered should be separated by the quantity into individuals order.
It issue is that getTags() returns null, and getTagIds gets "Call to a member function getTagIds() on null" when it gets to the next loop.
Is there a reason for why getTags() returns null?
private function transformOrderLines(OrderEntity $order): array
{
/**
* TODO: If we need to send advanced prices,
* the price value of the the lines array should be changed to caldulate the advanced price,
* with the built in quantity calculator
*/
$lines = [];
foreach ($order->getLineItems() as $orderLine) {
$hasDsmServiceItemTag = $orderLine->getProduct()->getTags();
$lines[] = [
'name' => $orderLine->getLabel(),
'sku' => substr($orderLine->getProduct()->getProductNumber(), 0, 19),
'price' => (string) ($orderLine->getProduct()->getPrice()->first()->getNet()
* $order->getCurrencyFactor()), //gets original price, calculates factor
'quantity' => (string) $orderLine->getQuantity()
];
}
$shipping = $this->transformShipping($order);
if ($shipping) {
$lines = array_merge($lines, $shipping);
}
return $lines;
}`
I also tried $orderLine->getProduct()->getTags()->getName() it also return "Call to a member function getTags() on null"
The problem is wherever the $order is fetched from the DB the orderLineItem.product.tag association is not included in the criteria.
For performance reasons shopware does not lazily load all association when you access them on entities, but you have to exactly define which associations should be included when you fetch the entities from the database.
For the full explanation take a look at the docs.

Linq2DB can't translate a mapped column in Where clause

I'm working with a legacy Oracle database that has a column on a table which stores boolean values as 'Y' or 'N' characters.
I have mapped/converted this column out like so:
MappingSchema.Default.SetConverter<char, bool>(ConvertToBoolean);
MappingSchema.Default.SetConverter<bool, char>(ConvertToChar);
ConvertToBoolean & ConvertToChar are simply functions that map between the types.
Here's the field:
private char hasDog;
[Column("HAS_DOG")]
public bool HasDog
{
get => ConvertToBoolean(hasDog);
set => hasDog = ConvertToChar(value);
}
This has worked well for simply retrieving data, however, it seems the translation of the following:
var humanQuery = (from human in database.Humans
join vetVisit in database.VetVisits on human.Identifier equals vetVisit.Identifier
select new HumanModel(
human.Identifier
human.Name,
human.HasDog,
vetVisit.Date,
vetVisit.Year,
vetVisit.PaymentDue
));
// humanQuery is filtered by year here
var query = from vetVisits in database.VetVisits
select new VetPaymentModel(
(humanQuery).First().Year,
(humanQuery).Where(q => q.HasDog).Sum(q => q.PaymentDue), -- These 2 lines aren't correctly translated to Y/N
(humanQuery).Where(q => !q.HasDog).Sum(q => q.PaymentDue)
);
As pointed out above, the .Where clause here doesn't translate the boolean comparison of HasDog being true/false to the relevant Y/N values, but instead a 0/1 and results in the error
ORA-01722: invalid number
Is there any way to handle this case? I'd like the generated SQL to check that HAS_DOG = 'Y' for instance with the specified Where clause :)
Notes
I'm not using EntityFramework here, the application module that this query exists in doesn't use EF/EFCore
You can define new mapping schema for your particular DataConnection:
var ms = new MappingSchema();
builder = ms.GetFluentMappingBuilder();
builder.Entity<Human>()
.Property(e => e.HasDog)
.HasConversion(v => v ? 'Y' : 'N', p => p == 'Y');
Create this schema ONCE and use when creating DataConnection

Perl SQL::Parser table alias substitution: works for SELECT column names but not for WHERE column names

I'm trying to parse some SQL queries stored in a log database -- I don't want to submit them to a SQL database, just to extract the fields used in the SELECT and WHERE clause.
I've been fiddling with several SQL parsers in Java, Python and Perl. The one that seems to work better for my problem are SQL::Parser and SQL::Statement. With those I was able to write the following code:
#!/usr/bin/perl
use strict;
use SQL::Parser;
use SQL::Statement;
use Data::Dumper;
my $sql = "SELECT sl.plate,sp.fehadop FROM sppLines AS sl ".
"JOIN sppParams AS sp ON sl.specobjid = sp.specobjid ".
"WHERE fehadop < -3.5 ";
my $parser = SQL::Parser->new();
my $stmt = SQL::Statement->new($sql,$parser);
printf("COMMAND [%s]\n",$stmt->command);
printf("COLUMNS \n");
my #columns = #{$stmt->column_defs()};
foreach my $column ( #columns)
{
print " ".$column->{value}."\n";
}
printf("TABLES \n");
my #tables = $stmt->tables();
foreach my $table ( #tables)
{
print " ".$table->{name}."\n";
}
printf("WHERE COLUMNS\n");
my $where_hash = $stmt->where_hash();
print Dumper($where_hash);
Sorry if it is too long, it is the smallest, self-contained example I could devise.
The output of this code is:
COMMAND [SELECT]
COLUMNS
spplines.plate
sppparams.fehadop
TABLES
spplines
sppparams
WHERE COLUMNS
$VAR1 = {
'arg1' => {
'value' => 'fehadop',
'type' => 'column',
'fullorg' => 'fehadop'
},
'op' => '<',
'nots' => {},
'arg2' => {
'str' => '-?0?',
'fullorg' => '-3.5',
'name' => 'numeric_exp',
'value' => [
{
'fullorg' => '3.5',
'value' => '3.5',
'type' => 'number'
}
],
'type' => 'function'
},
'neg' => 0
};
The parser returns the name of columns (obtained through a call to $stmt->column_defs()) already renamed with the real tables names (e.g. spplines.plate instead of s1.plate) -- this is what I want.
I also want the names of the columns used in the WHERE clause.
I already know how to recursively parse the results of $stmt->where_hash() (didn't include the code to make the post clear), but even from dumping its contents I can see that the column names are not associated with the tables.
I would like to ensure that the columns names in the WHERE clause are also preceded by the tables name. After parsing the results of $stmt->where_hash() I would get sppparams.fehadop instead of fehadop.
Is this possible with SQL::Parser?
Thanks
(big edit -- tried to make the question clearer)
Since SQL::Statement has an eval_where, I suspect there might be a better way, but you can try a function like this:
get_column($stmt->column_defs(), $where_hash->{arg1});
sub get_column {
my ($columns, $arg) = #_;
return $arg->{fullorg} if ($arg->{type} ne 'column');
foreach my $col (#$columns) {
return $col->{value} if ($col->{fullorg} eq $arg->{fullorg});
my ($name) = ( $col->{fullorg} =~ /([^.]+)$/);
return $col->{value} if ($name eq $arg->{fullorg});
}
return $arg->{fullorg};
}

The nested query does not have the appropriate keys

Firstly I have a function which takes 2 parameters( longitude, latitude).
RETURNS TABLE
AS
RETURN
(
select dbo.GeoCalculateDistance (#lat1Degrees,#lon1Degrees,Latitude,Longitude) as Distance, PKRestaurantId as PkKeyId from StRestaurant
)
And as you realise, I have a table that called StRestaurant. In this table I have 4 columns(PkRestaurantId, RegionId , Longitude, Latitude).
And, I need a method that takes 4 parameters.
public List<RestaurantDetailDto> GetRestaurant(int regionid, decimal latitude, decimal longitude, OrderType orderType)
{}
This method will give the restauants around me. But if I want to systematize this list with distance, I must join my Restaurant table and the function. Here is my query.
var query = from restaurant in context.StRestaurant
join distance in context.CalculateDistanceTable(latitude, longitude) on restaurant.PKRestaurantId equals distance.PkKeyId
where restaurant.FKRegionId == regionid
select new
{
Restaurant = restaurant,
DistanceTable = distance,
};
And then I am checking the orderType,
switch (orderType)
{
case OrderType.Distance:
query = query.OrderBy(x => x.DistanceTable.Distance);
break;
// and the anothers
}
Lastly, I am trying to take this list as;
var queryResult = query.ToList();
All the time I took this error :
The nested query does not have the appropriate keys.
I also try the above query but it return with the same error :s
var query = context.StRestaurant.Where(x => x.FKRegionId == regionid && x.IsActive).Join(
context.CalculateDistanceTable(latitude, longitude),
restaurant => restaurant.PKRestaurantId,
result => result.PkKeyId,
(restaurant, result) => new
{
Restaurant = restaurant,
MinumumPackagePrice = restaurant.StRestaurantRegionRelation.FirstOrDefault(x => x.FKRestaurantId == restaurant.PKRestaurantId).MinumumPackageCharge,
DistanceTable = result,
RestaurantImage = restaurant.StRestaurantImage.Where(x => x.IsDefault && x.FKRestaurantId == restaurant.PKRestaurantId),
}
);
Please help!!
I've seen this before when doing an .Include() on the result. I imagine your projection (in the second example) might be doing this internally. Could you add this to the first part?
In this case, I've had to add the .Include() on the source table:
from a in context.A.Include("relationship")
join b in context.MyFunction(...)
...
There are a some things that you can try here. First, rewrite your SQL function so that it has a primary key:
CREATE FUNCTION CalculateDistanceTable
(
-- Add the parameters for the function here
#lat1Degrees float,
#lon1Degrees float
)
RETURNS
#RestaurantDistances TABLE
(
-- Add the column definitions for the TABLE variable here
PkKeyId int NOT NULL primary key,
Distance float NOT NULL
)
AS
BEGIN
INSERT INTO #RestaurantDistances
SELECT dbo.GeoCalculateDistance(#lat1Degrees, #lon1Degrees, Latitude, Longitude) AS Distance, PKRestaurantId AS PkKeyId
FROM StRestaurant
RETURN
END
GO
Also, you can try changing your LINQ join to use anonymous types to perform the join.
var query = from restaurant in context.StRestaurant
join distance in context.CalculateDistanceTable(latitude, longitude) on new { Key = restaurant.PKRestaurantId } equals new { Key = distance.PkKeyId }
where restaurant.FKRegionId == regionid
select new
{
Restaurant = restaurant,
DistanceTable = distance,
};
If neither one of these helps let me know and I'll try to update this answer as appropriate.

Inserting 2D Values of Array into SQL

Right now, I have looped a form which in the end gives me a 2D Array.
Array 0D
User Arrays 1D
User Fields 2D
Array ( [1] => Array ( [fname] => qweqwe [lname] => qwewqe [email] => qwewqe [age] => wewqe ) [2] => Array ( [fname] => 123123 [lname] => 123123 [email] => 23123 [age] => 23123 ) )
This is an example of what I get when I type in rubbish into my fields.
To check if I could get the values for each form, I used this:
$i = $_POST['number'];
$corporate = $_POST['corporate'];
$x = 1;
print_r($corporate);
while($x <= $i)
{
echo "The first name first name".$corporate[$x]["fname"].".";
}
Using this, I would attain the first name of the first user, followed by the second and so on. This proves that I can get the 2D values from my forms.
What I have to do now is to insert those values into my table. Keep in mind, my 1D contains values of each user. 2D is the values itself.
mysql_query("INSERT INTO students ('fname','lname','email', 'age') VALUES
I have no idea what to put after that. Any help would be appreciated.
You need to add a set of data values to insert. These would be in the form ("Robert","Brown","Robert.Brown#uni.com","34")("Robert","Smith","Robert.Smith#uni.com","33")
What version of PHP are you using?
for php5.3 you could try:
$values = array();
foreach($corporate as $line){
$values[] = "('".implode("','",array_map(function($x){ return addslashes($x); })) . "')";
}
$query = "INSERT INTO students ('fname','lname','email', 'age') VALUES";
$query .= implode($values);
$record = mysql_query($query);
Otherwise, try:
$values = array();
foreach($corporate as $line){
foreach($line as $i=>$item) $line[$i] = addslashes($item);
$values[] = "('".implode("','",$line) . "')";
}
$query = "INSERT INTO students ('fname','lname','email', 'age') VALUES";
$query .= implode($values);
$record = mysql_query($query);
To solve the second part of your problem, you need to edit the table definitions and remove the "NOT NULL" definition that sits on each field. Do you have php my admin on the server? you could do it through that by editing the table and fields, otherwise you could run the sql using ALTER TABLE. Let me know if you want more information on that.
Well, using your query, understanding what it means in depth, I finally got it working.
This is the code that I used:
foreach($corporate as $line)
{
$values[] = "('".implode("','",$line) . "')";
echo "<br />";
print_r($values);
$a = implode(",", $values);
echo $a;
}
$query = "INSERT into students (fname, lname,email,age) VALUES $a";
$sql = mysql_query($query);
This works fine on my database, works like a charm.
However, when I try this on my friends DB or an Online DB, I get an error which requires me to give every field a value. For some reason, it cannot enter NULL values.
I'm trying to figure out why, but the gist of my problem has been solved.
If you know what is causing my error, feel free to comment. Thanks.